1 Run PCAnsgd for PWS populations

Using the ‘PWSonly’ sites (~770k snps) Running PCAngsd requires several steps

1.1 Steps

1.1.2 Using bcftools to subset the VCF file using prune.in file

1.1.3 Convert VCF to the beagle format and run PCAnsgd

#create vcf files with only prune.in sites
#index the vcf first
bcftools index home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz

bcftools view -R /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/PWSonly_NS0.5_maf05_75_5_0.5.prune.in.sites.txt /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/PWSonly_maf05_pruned.vcf
bgzip /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/PWSonly_maf05_pruned.vcf

#Create beagle files (create_beagle_PWS.sh)
#e.g.
vcftools --gzvcf /home/ktist/ph/data/new_vcf/MD7000/plinkfiles/PWSonly_maf05_pruned.vcf.gz --chr chr1 --out /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c1 --BEAGLE-PL 

gzip /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c1.BEAGLE.PL 

#Run PCAngsd (pcangsd_pws.sh)
#e.g. 
python /home/jamcgirr/apps/pcangsd/pcangsd.py -beagle /home/ktist/ph/data/new_vcf/MD7000/beagle/PWSonly_pruned_c1.BEAGLE.PL.gz -o /home/ktist/ph/data/angsd/PCAngsd/PWSonly_maf05_chr1 -threads 16 

1.2 Results of PCAngsd

pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pop_info<-pop_info[,c("Sample","Population.Year","pop","Year.Collected")]
colnames(pop_info)[4]<-"year"
pops<-pop_info[pop_info$pop=="PWS",]

pcols<-c("#d7b5d8","#df65b0","#dd1c77","#980043")
Plots<-list()
chr<-paste0("chr", c(1:23,25:26) ) #exclude chr24
for (i in 1:length(chr)){
    C <- as.matrix(read.table(paste0("../Data/PCAangsd/PWSonly_maf05_",chr[i],".cov")))
    e <- eigen(C)
    pca <-data.frame(Sample=pops$Sample, 
                     pop=pops$pop,
                     year=pops$year,
                     PC1=e$vectors[,1],PC2=e$vectors[,2],
                     PC3=e$vectors[,3],PC4=e$vectors[,4],
                     PC5=e$vectors[,5],PC6=e$vectors[,6],
                     PC7=e$vectors[,7],PC8=e$vectors[,8],
                     stringsAsFactors=FALSE)
    
    prop_explained <- c()
    for (s in e$values[1:10]) {
        #print(s / sum(e$values))
        prop_explained <- c(prop_explained,round(((s / sum(e$values))*100),2))
    }
    #write.csv(pca, paste0("../Output/PCA/PWSonly_pca_",chr[i],".csv"), row.names = F)
    Plots[[i]]<-ggplot()+
        geom_point(data = pca, aes(x = PC1, y = PC2, fill = factor(year), color = factor(year), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,21), guide="none")+
        scale_fill_manual(values=paste0(pcols,"99"), guide="none")+
        scale_color_manual(values=pcols[1:4])+
        xlab(paste("PC 1: ", prop_explained[1],"%\n",sep = ""))+
        ylab(paste("PC 2: ", prop_explained[2],"%\n",sep = ""))+
        theme_bw()+
        ggtitle(paste0(chr[i]))+
        guides(shape = guide_legend(override.aes =c(23,25,3,21)), fill=guide_legend(override.aes =paste0(pcols,"99")))+theme(legend.title = element_blank())
}


{pdf("../Output/PCA/PWSonly_PCA_byChromosome.pdf",width = 35, height = 30)
do.call(grid.arrange, c(Plots, ncol=5))
dev.off()
}

g <- arrangeGrob(do.call(grid.arrange, c(Plots, ncol=5)))
ggsave(g, file="../Output/PCA/PWSonly_PCA_byChromosome.png",width = 35, height = 30)


The separation among years are not so clear but clustering into 3 groups are visible in Chr4,8,15,20.


2 Look at each chromosome, starting with Chr15

2.1 PWS Chromosome 15 grouped into 3 (PC1 >10%)

Chr15 shows the largest proportion explained by PC1 (strongest clustering)

#proportion of year in each group
ch15<-read.csv("../Output/PCA/PWSonly_pca_chr15.csv")
gp1<-ch15[ch15$PC1<0,]
gp2<-ch15[ch15$PC1>=0&ch15$PC1<0.075,]
gp3<-ch15[ch15$PC1>0.075,]

table(gp1$year)
#1991 1996 2007 2017 
#  25   39   23   22 
  
table(gp2$year)
#1991 1996 2007 2017 
#  22   28   21   23 
table(gp3$year)
#1991 1996 2007 2017 
#11    5    2   11 

no<-table(pops$year)
#1991 1996 2007 2017 
#  58   72   46   56 

gp1$group<-"Group1"
gp2$group<-"Group2"
gp3$group<-"Group3"
c15<-rbind(gp1,gp2,gp3)
c15$yr.pop<-paste0(c15$pop, substr(c15$year,3,4))
write.csv(c15,"../Output/PCA/chr15_PCAgroups.csv")

ggplot()+
        geom_point(data = c15, aes(x = PC1, y = PC2, fill = factor(year), color = factor(year), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,21), guide="none")+
        scale_fill_manual(values=paste0(pcols,"99"), guide="none")+
        scale_color_manual(values=pcols[1:4])+
        xlab("PC 1")+
        ylab("PC 2")+
        theme_bw()+
        ggtitle("Chr15")+
        guides(shape = guide_legend(override.aes =c(23,25,3,21)), fill=guide_legend(override.aes =paste0(pcols,"99")))+theme(legend.title = element_blank())+
     stat_ellipse(data=c15, aes(x=PC1, y=PC2, group=group), level=0.999,color="gray50", size=0.2)+
    annotate("text", x=-0.06, y=0.22, label="Group 1")+
    annotate("text", x=0.01, y=0.18, label="Group 2")+
    annotate("text", x=0.12, y=0.18, label="Group 3")
ggsave("../Output/PCA/Chr15_PCA_withGroups.png", width = 6, height = 4.5,dpi=300 )

2.1.1 Create a summary of group proportions in each year

#Create a summary
ch15_summary<-data.frame(year=c(1991,1996,2007,2017))
ch15_summary$Group1<-as.vector(table(gp1$year))
ch15_summary$Group2<-as.vector(table(gp2$year))
ch15_summary$Group3<-as.vector(table(gp3$year))

#quick chi-square test 
chisq.test(ch15_summary[,2:4])
#   Pearson's Chi-squared test
#X-squared = 10.667, df = 6, p-value = 0.09922
#2007 vs. 2017
chisq.test(ch15_summary[c(3,4),2:4])
#X-squared = 5.4156, df = 2, p-value = 0.06668

c15m<-melt(ch15_summary, id.vars="year")
ggplot(c15m, aes(x=factor(year), y=value, fill=variable))+
    geom_bar(stat="identity", width=0.5, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("Year")+ggtitle("PWS Chr15")
ggsave("../Output/PCA/PWS_ch15_prop_indivi_in3groups.png", width = 6, height = 4, dpi=150)

The proportions of the 3 groups change over time (marginally significantly different.

2.1.2 How and where do groups differ? Plot Fst and Dxy along the chromosome

Use “PopGenome” package to assess Fst, Dxy, and pi.

#Calculate Fst among the 3 groups using PopGenome
# read chr15 from the 'PWSonly' file
pws <- readData("../Data/new_vcf/PWS/PWSonly_chr15/", format = "VCF", include.unknown = TRUE, FAST = TRUE)

#assign groups
pops$group<-"Group1"
pops$group[pops$Sample %in% gp2$Sample]<-"Group2"
pops$group[pops$Sample %in% gp3$Sample]<-"Group3"
populations <- split(pops$Sample, pops$group)

pws<-set.populations(pws, populations, diploid = T)

# set the chromosome size
chr15<-28713521

# set window size and window jump
window_size <- 50000
window_jump <- 10000
# make a sliding window dataset
pws_sw <- sliding.window.transform(pws, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-pws_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
pws_sw <- diversity.stats(pws_sw, pi = TRUE)
pws_sw <- F_ST.stats(pws_sw, mode = "nucleotide")

# extract nucleotide diversity and correct for window size
nd <- pws_sw@nuc.diversity.within/50000

# make group name vector
groupnames <- sort(unique(pops$group))
# set population names
colnames(nd) <- paste0(groupnames, "_pi")

# extract fst values
fst <- t(pws_sw@nuc.F_ST.pairwise)

# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(pws_sw, between = T)[[2]]/50000

# get column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
pws_data <- as_tibble(data.frame(window, nd, fst, dxy))

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1: nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-pws_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr15 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr15,1 ))
        ggsave(paste0("../Output/PCA/PWSonly_Diversity_stats_chr15_",pop1," vs.", pop2,".png"), width = 9, height = 4, dpi=150)
    }



Position 0-16.5Mb shows a strong differentiation among groups.

2.1.3 Check if an inversion is visible in the genotype-plot

The proportion of Group2 is higher in PWS96 and PWS07 -> More heterozygous snps in PWS96 &PWS07?

2.1.4 Calculate Heterozygosity from ANGSD .saf files

-Can calculate heterozygosity for an entire chromosome or genome only (not useful for assessing within a chromosme)

#estimate heterozygosity from .saf from ANGSD -> can't divide het into regions  
popnames<-c("PWS91","PWS96","PWS07","PWS17")

het<-data.frame(pop=popnames)
for (i in 1:4){
    a<-scan(paste0("../Data/new_vcf/angsd/fromBam/unfolded/",popnames[i],"_unfolded.sfs"))
    het$He[i]<-a[2]/sum(a)
}

het
#   pop     he_bam
#1 PWS91 0.02653463
#2 PWS96 0.02865388
#3 PWS07 0.02564408
#4 PWS17 0.02336336

kable(het, "html") %>%
  kable_styling(full_width = F)

2.1.5 Compare heterozygosity per region per group per year using bcftools

The following code is referred as “Box1”

#Calculate heterozygosity per window using bcftools (het_stats_PWS91.sh)
#e.g. 
bcftools stats -r chr15:0-100000 -s - /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly91_maf05.vcf.gz | grep '^PSC' > /home/ktist/ph/data/new_vcf/MD7000/population/PWS91/PWS91_stats_1
bcftools stats -r chr15:100000-200000 -s - /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly91_maf05.vcf.gz | grep '^PSC' > /home/ktist/ph/data/new_vcf/MD7000/population/PWS91/PWS91_stats_2
# for for all regions...
# run slurm scripts (het_statsXYX.sh)

#Convert the output files to tab-deliminted, and cat them(catFiles_PWS91.sh)
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > PWS91_statsFile

2.1.6 Results of observed heterozygosity (Ho) per year for each group

  • Summarize Ho based on two regions (region1=high-Fst (~16.5Mb) vs. region2=low-Fst(16.5~end))
## Read the stats files and create het summary
# Calculate Ho and He from bcftools stats output files (stats from PWSonly files)
sfiles<-list.files("../Data/new_vcf/PWSonly/", pattern="_chr15_statsFile")
Het_sum<-data.frame()
#c15<-read.csv("../Output/PCA/chr15_PCAgroups.csv", row.names = 1)
for (i in 1:length(sfiles)){
    df<-read.table(paste0("../Data/new_vcf/PWSonly/", sfiles[i]), sep="\t", header=F)
    pname<-gsub("_chr15_statsFile",'',sfiles[i])
    pname<-gsub("PWSonly_",'', pname)
    df<-df[,c(3:10, 14)]
    colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
    df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    
    df$He<-2*df$p*df$q
    df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
    
    df$Group<-"Group1"
    df$Group[df$Sample %in% c15$Sample[c15$group=="Group2"]]<-"Group2"
    df$Group[df$Sample %in% c15$Sample[c15$group=="Group3"]]<-"Group3"
    
    Ho<-aggregate(df[,"Ho"], by=list(df$window_no, df$Group), mean )
    He<-aggregate(df[,"He"], by=list(df$window_no,df$Group), mean )
    het<-cbind(Ho, He$x)
    colnames(het)<-c("window_id","Group","Ho","He")
    write.csv(het,paste0("../Output/Stats_window/PWSonly_chr15_Heteroz_",pname,"_maf05.csv"))
    
    het$window<-as.integer(gsub(paste0(pname,"_stats_"),'',het$window_id))
    het$loc<-"region1"
    het$loc[het$window>165]<-"region2"
    
    groupHo<-aggregate(het[,"Ho"], by=list(het$Group, het$loc), mean , na.rm=T)
    colnames(groupHo)<-c("Group","Region","Ho")
    groupHo$year<-pname
    Het_sum<-rbind(Het_sum,groupHo)
}

write.csv(Het_sum, "../Output/Stats_window/PWSonly_chr15_Hetero_group_summary.csv")


Observed heterozygosity (Ho) is higher in Group2 than Group1 in Region 1 (the hypothetical inversion region). Heterozygosity appeared to be suppressed in Group1.


2.2 Chr15 group proportions in other populations

2.2.1 *3 groups of PWS are the same for all populations considered

all pops no TB

2.2.2 Summary of group proportions for each pop

#from Chr_Analysis.R
gp15<-read.csv("../Output/PCA/chr15_PCAgroups.csv", row.names = 1)
#double check the same individulas are in the same groups for PWS pops

setequal(gp15$Sample[gp15$Group=="Group1"&gp15$pop=="PWS"], c15$Sample[c15$Group=="Group1"])
setequal(gp15$Sample[gp15$Group=="Group3"&gp15$pop=="PWS"], c15$Sample[c15$Group=="Group3"])

pop.sum<-gp15 %>% count(Group, yr.pop)

pop.sum$yr.pop<-factor(pop.sum$yr.pop, levels=c("PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))
ggplot(data=pop.sum, aes(x=yr.pop, y=n, fill=factor(Group)))+
    geom_bar(position="fill", stat="identity", color="gray30")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"), labels=c("Group1","Group2","Group3"))+
    theme_light()+ggtitle("Chr15")+
    xlab("")+ylab("Proportion")+theme(legend.title = element_blank())
ggsave("../Output/PCA/Chr15_3groups_barplot_allPops.png", width = 8, height = 5.5, dpi=300)

The majority of CA individuals are in Group 2 & 3, while others are Group 1 & 2.
PWS populations are uniquely differnet from SS pops.

2.2.3 Compare heterozygosity among groups for all pops

2.2.3.1 heterozygosity is higher in Group2 (The same pattern as in PWS)

# Calculate Ho and He from bcftools stats output files
sfiles<-list.files("../Data/new_vcf/ch15/", pattern="_maf05_statsFile")
groups<-paste0("group",1:3)
Het<-data.frame()
for (i in 1:length(sfiles)){
    df<-read.table(paste0("../Data/new_vcf/ch15/", sfiles[i]), sep="\t", header=F)
    df<-df[,c(3:10, 14:15)]
    colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
    df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$He<-2*df$p*df$q
    df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
    
    Ho<-aggregate(df[,"Ho"], by=list(df$window_no), mean )
    He<-aggregate(df[,"He"], by=list(df$window_no), mean )
    het<-cbind(Ho, He$x)
    colnames(het)<-c("window_id","Ho","He")
    het$Group<-paste0("Group",i)
    het$window<-as.integer(gsub(paste0("ph_ch15_",groups[i],"_stats_"),'',het$window_id))
    Het<-rbind(Het,het)
}
 
Het$loc<-"region1"
Het$loc[Het$window>165]<-"region2"
write.csv(Het, "../Output/PCA/Chr15_Ho_byGroups.csv")    

groupHo<-aggregate(Het[,"Ho"], by=list(Het$Group, Het$loc), mean , na.rm=T)
colnames(groupHo)<-c("Group","Region","Ho")
write.csv(groupHo, "../Output/Stats_window/Chr15_Hetero_group1-3_summary.csv")

#Plot the results
gcols<-c("#FB687B","#48ABE3","#75BA76")
ggplot()+
    geom_boxplot(data=Het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=groupHo, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')
ggsave("../Output/PCA/Chr15_Ho.allpops_in.tworegions.png", width = 6, height = 4, dpi=300)

2.2.3.2 Heterozygosity using maf0.01 vcf files for comparison

Ho patterns are highly similar to that of maf0.05.

# Ho using maf01 files for comparison
sfiles<-list.files("../Data/new_vcf/ch15/", pattern="_maf01_statsFile")
c15<-read.csv("../Output/PCA/chr15_PCAgroups.csv", row.names = 1)
groups<-paste0("group",1:3)
Het<-data.frame()
for (i in 1:length(sfiles)){
    df<-read.table(paste0("../Data/new_vcf/ch15/", sfiles[i]), sep="\t", header=F)
    df<-df[,c(3:10, 14:15)]
    colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
    df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$He<-2*df$p*df$q
    df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
    
    Ho<-aggregate(df[,"Ho"], by=list(df$window_no), mean )
    He<-aggregate(df[,"He"], by=list(df$window_no), mean )
    het<-cbind(Ho, He$x)
    colnames(het)<-c("window_id","Ho","He")
    het$Group<-paste0("Group",i)
    het$window<-as.integer(gsub(paste0("ph_ch15_",groups[i],"_maf01_stats_"),'',het$window_id))
    Het<-rbind(Het,het)
}
 
Het$loc<-"region1"
Het$loc[Het$window>165]<-"region2"
write.csv(Het, "../Output/PCA/Chr15_Ho_byGroups_maf01.csv")    

groupHo<-aggregate(Het[,"Ho"], by=list(Het$Group, Het$loc), mean , na.rm=T)
colnames(groupHo)<-c("Group","Region","Ho")
write.csv(groupHo, "../Output/Stats_window/Chr15_Hetero_group1-3_summary_maf01.csv")

#Plot the results
gcols<-c("#FB687B","#48ABE3","#75BA76")
ggplot()+
    geom_boxplot(data=Het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=groupHo, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')
ggsave("../Output/PCA/Chr15_Ho.allpops_in.tworegions_maf01.png", width = 6, height = 3.5, dpi=300)


* very similar to maf0.05, meaning no need to use maf01 files



3 Chr8

3.1 PWS Chromosome 8 grouped into 3 (PC1 = 5.8%)

#proportion of year in each group
ch8<-read.csv("../Output/PCA/PWSonly_pca_chr8.csv")
gp1<-ch8[ch8$PC1<0,]
gp2<-ch8[ch8$PC1>0&ch8$PC1<0.1,]
gp3<-ch8[ch8$PC1>0.1,]

table(gp1$year) #140
#1991 1996 2007 2017 
#  37   51   27   25 
table(gp2$year) #83
#1991 1996 2007 2017 
#  19   19   17   28 
table(gp3$year) #9
#1991 1996 2007 2017 
#   2    2    2    3 

no<-table(pops$year)
#1991 1996 2007 2017 
#  58   72   46   56 

gp1$group<-"Group1"
gp2$group<-"Group2"
gp3$group<-"Group3"
c8<-rbind(gp1,gp2,gp3)
write.csv(c8, "../Output/PCA/PWSonly_with.groups_pca_chr8.csv")

ggplot()+
        geom_point(data = c8, aes(x = PC1, y = PC2, fill = factor(year), color = factor(year), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,21), guide="none")+
        scale_fill_manual(values=paste0(pcols,"99"), guide="none")+
        scale_color_manual(values=pcols[1:4])+
        xlab(paste("PC 1"))+
        ylab(paste("PC 2"))+
        theme_bw()+
        ggtitle("Chr8")+
        guides(shape = guide_legend(override.aes =c(23,25,3,21)), fill=guide_legend(override.aes =paste0(pcols,"99")))+theme(legend.title = element_blank())+
     stat_ellipse(data=c8, aes(x=PC1, y=PC2, group=group), color="gray50", size=0.2,level=0.995)+
    annotate("text", x=-0.03, y=0.25, label="Group 1")+
    annotate("text", x=0.035, y=0.2, label="Group 2")+
    annotate("text", x=0.18, y=0.2, label="Group 3")
ggsave("../Output/PCA/Ch8_PCA_withGroups_noTB.png", width = 6.5, height = 4.5, dpi=300)
#TB is in 1 group

3.1.1 Calculate the group proportions for each year

#Create a summary
ch8_summary<-data.frame(year=c(1991,1996,2007,2017))
ch8_summary$Group1<-as.vector(table(gp1$year))
ch8_summary$Group2<-as.vector(table(gp2$year))
ch8_summary$Group3<-as.vector(table(gp3$year))

#quick chi-square test 
chisq.test(ch8_summary[,2:4])
#   Pearson's Chi-squared test
#X-squared = 9.4357, df = 6, p-value = 0.1505

chisq.test(ch8_summary[c(2,4),2:4]) #PWS96 vs. PWS17
#X-squared = 8.9581, df = 2, p-value = 0.01134
#
c8m<-melt(ch8_summary, id.vars="year")
ggplot(c8m, aes(x=factor(year), y=value, fill=variable))+
    geom_bar(stat="identity", width=0.5, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("Year")+ggtitle("PWS Chr8")
ggsave("../Output/PCA/PWS_ch8_prop_indivi_in3groups.png", width = 6, height = 4, dpi=150)

Chr8 group proportions also shift with years.

3.1.2 Plot Fst and Dxy along the chromosome

# read chr8 from the 'PWSonly' file
pws <- readData("../Data/new_vcf/PWSonly/PWSonly_chr8/", format = "VCF", include.unknown = TRUE, FAST = TRUE)

pops<-pop_info[pop_info$pop=="PWS",]
#assign groups
pops$group<-"Group1"
pops$group[pops$Sample %in% gp2$Sample]<-"Group2"
pops$group[pops$Sample %in% gp3$Sample]<-"Group3"

populations <- split(pops$Sample, pops$group)

pws<-set.populations(pws, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr8<-chrsize$V3[chrsize$V1=="chr8"]

# set window size and window jump
window_size <- 50000
window_jump <- 10000
# make a sliding window dataset
pws_sw <- sliding.window.transform(pws, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-pws_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
pws_sw <- diversity.stats(pws_sw, pi = TRUE)
pws_sw <- F_ST.stats(pws_sw, mode = "nucleotide")

# extract nucleotide diversity and correct for window size
nd <- pws_sw@nuc.diversity.within/50000

# make group name vector
groupnames <- sort(unique(pops$group))
# set population names
colnames(nd) <- paste0(groupnames, "_pi")

# extract fst values
fst <- t(pws_sw@nuc.F_ST.pairwise)

# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(pws_sw, between = T)[[2]]/50000

# get column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
pws_data <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(pws_data,"../Output/PCA/PWSonly_chr8_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1: nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-pws_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr8 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr8,1 ))
        ggsave(paste0("../Output/PCA/PWSonly_Diversity_stats_chr8_",pop1," vs.", pop2,".png"), width = 9, height = 4, dpi=150)
    }


Position 23Mb-end shows high Fst among groups.


3.1.3 Genotype plot for each year - inversion is not clearly visible

Chr8 is suggested to have a ‘putative inversion’ in Petrou et al. 2021

3.1.4 Mean Fst between groups

3.1.5 Mean Fst between groups over years

#calculate mean Fst between groups within each year
pws <- readData("../Data/new_vcf/PWSonly/PWSonly_chr8/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
#assign groups
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop=="PWS",]

pops$group<-"Group1"
pops$group[pops$Sample %in% c8$Sample[c8$group=="Group2"]]<-"Group2"
pops$group[pops$Sample %in% c8$Sample[c8$group=="Group3"]]<-"Group3"

pops$id<-paste0(pops$group,".",pops$Year.Collected)
populations2 <- split(pops$Sample, pops$id)

pws2<-set.populations(pws, populations2, diploid = T)
pws_sw2 <- sliding.window.transform(pws2, width = 50000, jump = 10000, type = 2)
pws_sw2 <- diversity.stats(pws_sw2, pi = TRUE)
pws_sw2 <- F_ST.stats(pws_sw2, mode = "nucleotide")
nd2 <- pws_sw2@nuc.diversity.within/50000
idnames <- names(pws2@populations)# sort(unique(pops$id))
colnames(nd2) <- paste0(idnames, "_pi")

fst2 <- t(pws_sw2@nuc.F_ST.pairwise)
dxy2 <- get.diversity(pws_sw2, between = T)[[2]]/50000

# get column names 
x <- colnames(fst2)
for (i in 1: length(idnames)){
    x<-sub(paste0("pop",i,"/"), paste0(idnames[i],"_"), x)
    x<-sub(paste0("pop",i,"$"), paste0(idnames[i]), x)
}
colnames(fst2)<-paste0("fst_",x)
colnames(dxy2)<-paste0("dxy_",x)

# crate sliding window info
windows<-pws_sw2@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#combine all data
pws_data2 <- as_tibble(data.frame(window, nd2, fst2, dxy2))
fstall<-pws_data2[,c(3, grep("fst", colnames(pws_data2)))]
fstm<-data.frame(Fst=colMeans(fstall[,2:67], na.rm=T))
fstm$groupA<-substr(rownames(fstm), 5,10)
fstm$groupB<-substr(rownames(fstm), 17,22)
fstm$yearA<-substr(rownames(fstm), 12,15)
fstm$yearB<-substr(rownames(fstm), 24,27)
fstm$year<- apply(fstm[,c("yearA","yearB")], 1, function(x) {if (x["yearA"]==x['yearB']) x["yearA"]
                                           else NA})

pcols<-c("#d7b5d8","#df65b0","#dd1c77","#980043")
fstm2<-fstm[!is.na(fstm$year),]
fstm2$comp<-paste0(fstm2$groupA,".vs.",fstm2$groupB)
ggplot(fstm2, aes(x=comp, y=Fst, fill=year))+
    geom_bar(stat="identity",position=position_dodge(width = 1))+
    theme_light()+xlab('')+
    scale_fill_manual(values=pcols)
ggsave("../Output/PCA/PWSonly_Fst_between.groups_eachYear.png", width = 7.5, height = 5, dpi=300)

ggplot(fstm2, aes(x=year, y=Fst, color=comp, group=comp))+
    geom_point()+
    geom_path ()+
    theme_light()+xlab('')+theme(legend.title = element_blank())+
    scale_fill_manual(values=pcols)
ggsave("../Output/PCA/PWSonly_ch8_Fst_overtime_amongGroups.png", width=6, height=4, dpi=200)

3.1.6 Calculate heterozygosity for each group as in chr15 (‘Box 1’)

#Calculate heterozygosity per window using bcftools (het_stats_PWS91.sh)
#e.g. 

bcftools stats -r chr15:0-230000 -s - /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly91_maf05.vcf.gz | grep '^PSC' > /home/ktist/ph/data/new_vcf/MD7000/population/PWS91/PWS91_stats_1
bcftools stats -r chr15:100000-200000 -s - /home/ktist/ph/data/new_vcf/MD7000/population/PWSonly91_maf05.vcf.gz | grep '^PSC' > /home/ktist/ph/data/new_vcf/MD7000/population/PWS91/PWS91_stats_2
#etc...

#cat all files (catFiles_PWS91.sh)
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > PWS91_statsFile

3.1.7 Process the bcftools stats file to obtain Ho and He

## Read the stats files and create het summary

# Calculate Ho and He from bcftools stats output files (stats from PWSonly files)
sfiles<-list.files("../Data/new_vcf/PWSonly/", pattern="_chr8_statsFile")
Het_sum<-data.frame()
for (i in 1:length(sfiles)){
    df<-read.table(paste0("../Data/new_vcf/PWSonly/", sfiles[i]), sep="\t", header=F)
    pname<-gsub("_chr8_statsFile",'',sfiles[i])
    pname<-gsub("PWSonly_",'', pname)
    df<-df[,c(3:10, 14:15)]
    colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
    df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    
    df$He<-2*df$p*df$q
    df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
    
    df$Group<-"Group1"
    df$Group[df$Sample %in% gp2$Sample]<-"Group2"
    df$Group[df$Sample %in% gp3$Sample]<-"Group3"
    
    Ho<-aggregate(df[,"Ho"], by=list(df$window_no, df$Group), mean )
    He<-aggregate(df[,"He"], by=list(df$window_no,df$Group), mean )
    het<-cbind(Ho, He$x)
    colnames(het)<-c("window_id","Group","Ho","He")
    write.csv(het,paste0("../Output/Stats_window/PWSonly_chr8_Heteroz_",pname,"_maf05.csv"))
    
    het$window<-as.integer(gsub(paste0(pname,"_stats_"),'',het$window_id))
    het$loc<-"region1"
    het$loc[het$window>165]<-"region2"
    
    groupHo<-aggregate(het[,"Ho"], by=list(het$Group, het$loc), mean , na.rm=T)
    colnames(groupHo)<-c("Group","Region","Ho")
    groupHo$year<-pname
    Het_sum<-rbind(Het_sum,groupHo)
}

write.csv(Het_sum, "../Output/Stats_window/PWSonly_chr8_Hetero_group_summary.csv")

3.1.8 Compare Heterozygosity levels among groups and between regions

#Create a figure
pops<-c("PWS91","PWS96","PWS07","PWS17")

Het<-data.frame()
for (i in 1:length(pops)){
    df<-read.csv(paste0("../Output/Stats_window/PWSonly_chr8_Heteroz_",pops[i],"_maf05.csv"), row.names = 1)
    df$window<-as.integer(gsub(paste0(pops[i],"_stats_"),'',df$window_id))
    df$loc<-"region1"
    df$loc[df$window>230]<-"region2"
    df$pop<-pops[i]
    Het<-rbind(Het,df)    
}

gcols<-c("#FB687B","#48ABE3","#75BA76")
Het$pop<-factor(Het$pop, levels=pops)
colnames(Het_sum)[4]<-"pop"
Het_sum$pop<-factor(Het_sum$pop, levels=pops)

ggplot()+
    geom_boxplot(data=Het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=Het_sum, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    facet_wrap(~pop)+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')+ggtitle("Chr8")
ggsave("../Output/PCA/PWS_Chr8_Ho.in.tworegions.png", , width = 8, height = 7, dpi=300)

3.2 Chr8 group proportions in other populations

TB clustered in one group. The rest are in 3 groups.

3.2.1 Create a summary of group proportions in each year

#from Chr_Analysis.R
gp8<-read.csv("../Output/chr/DP7000/chr8/chr8_PCAgroups_updated.csv", row.names = 1)
## make sure groupings are the same for all vs. PWSonly

setequal(gp8$Sample[gp8$Group=="Group1"&gp8$pop=="PWS"], c8$Sample[c8$Group=="Group1"])
setequal(gp8$Sample[gp8$Group=="Group3"&gp8$pop=="PWS"], c8$Sample[c8$Group=="Group3"])


pop.sum<-gp8 %>% count(Group, yr.pop)

pop.sum$yr.pop<-factor(pop.sum$yr.pop, levels=c("PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))
ggplot(data=pop.sum, aes(x=yr.pop, y=n, fill=factor(Group)))+
    geom_bar(position="fill", stat="identity", color="gray30")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"), labels=c("Group1","Group2","Group3"))+
    theme_light()+
    xlab("")+ylab("Proportion")+theme(legend.title = element_blank())
ggsave("../Output/PCA/Chr8_3groups_barplot_allPops.png", width = 8, height = 5.5, dpi=300)

  • CA and PWS17 have larger proportion of Group2 (which has higher Ho than group1 in the highFst region)



3.2.2 Look at the overlap of individuals in Group3/Group2 of Chr15 and Chr8 (PWSonly)



c15g3<-c15$Sample[c15$Group=="Group3"]
c8g3<-c8$Sample[c8$group=="Group3"]
x<-list(chr8=c8g3,chr15=c15g3)
p3<-ggvenn(x, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

c15g2<-c15$Sample[c15$Group=="Group2"]
c8g2<-c8$Sample[c8$group=="Group2"]
x2<-list(chr8=c8g2,chr15=c15g2)
p2<-ggvenn(x2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")

venn<-ggdraw()+
        draw_plot(p2,x=0,y=0,width=0.5,height=1)+
        draw_plot(p3,0.5,0,0.5,1)+
        draw_plot_label("PWS", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch8.ch15.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

* Chr8 and Chr15 outliers (Group3 individuals) are not the same (only 3 samples belong to group3 in both)


4 Chr20

4.1 Look at PWS Chromosome 20: → grouped into 3

  • Clustering patterns are slightly different for PWS only vs. with other populations

  • CA individuals have an inversion at the beginning of the chromosome

  • TB also separates into 3 groups (due to the presence of the inversion)

All populations No TB


4.1.1 Start with PWS only

#proportion of year in each group
ch20<-read.csv("../Output/PCA/PWSonly_pca_chr20.csv")
gp1<-ch20[ch20$PC1>0.02,]
gp3.1<-ch20[ch20$PC1<(-0.15)&ch20$PC2>0,]
gp3.2<-ch20[ch20$PC1<(-0.075)&ch20$PC2<0,]
gp3<-rbind(gp3.1,gp3.2)
gp2<-ch20[!(ch20$Sample %in% c(gp1$Sample, gp3$Sample)),  ]

table(gp1$year) #99
#1991 1996 2007 2017 
#  24   28   19   28 
table(gp2$year) #110
#1991 1996 2007 2017 
#  28   40   18   24  
table(gp3$year) #9
#1991 1996 2007 2017 
#   6    4    9    4  

gp1$group<-"Group1"
gp2$group<-"Group2"
gp3$group<-"Group3"
c20<-rbind(gp1,gp2,gp3)
write.csv(c20, "../Output/PCA/PWSonly_with.groups_pca_chr20.csv")

pcols<-c("#d7b5d8","#df65b0","#dd1c77","#980043")
ggplot()+
        geom_point(data = c20, aes(x = PC1, y = PC2, fill = factor(year), color = factor(year), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,21), guide="none")+
        scale_fill_manual(values=paste0(pcols,"99"), guide="none")+
        scale_color_manual(values=pcols[1:4])+
        xlab(paste("PC 1"))+
        ylab(paste("PC 2"))+
        theme_bw()+
        ggtitle("Chr20")+
        guides(shape = guide_legend(override.aes =c(23,25,3,21)), fill=guide_legend(override.aes =paste0(pcols,"99")))+theme(legend.title = element_blank())+
     stat_ellipse(data=c20[c20$group!="Group2",], aes(x=PC1, y=PC2, group=group), color="gray50", size=0.2,level=0.99)+
     geom_ellipse(aes(x0=-0.05, y0=0.08,  angle=-20.15, a=0.22, b=0.05), color="gray50", size=0.2)+geom_path()+
    annotate("text", x=0.05, y=0.2, label="Group 1")+
    annotate("text", x=-0.1, y=0.32, label="Group 2")+
    annotate("text", x=-0.22, y=-0.2, label="Group 3")
ggsave("../Output/PCA/PWSonly_Ch20_PCA_withGroups.png", width = 6, height = 4.5, dpi=300)
#TB is in 1 group

4.1.2 Porportion of each groups per year

#Create a summary
ch20_summary<-data.frame(year=c(1991,1996,2007,2017))
ch20_summary$Group1<-as.vector(table(gp1$year))
ch20_summary$Group2<-as.vector(table(gp2$year))
ch20_summary$Group3<-as.vector(table(gp3$year))

ch20_summary$Group1<-as.vector(table(c20$year[c20$group=="Group1"]))
ch20_summary$Group2<-as.vector(table(c20$year[c20$group=="Group2"]))
ch20_summary$Group3<-as.vector(table(c20$year[c20$group=="Group3"]))

#matrix to be tested
X<-ch20_summary[,2:4]
rownames(X)<-ch20_summary$year
#quick chi-square test 
chisq.test(ch20_summary[,2:4])
#X-squared = 9.0619, df = 6, p-value = 0.1701

chisq.test(ch20_summary[c(2,3),2:4]) #PWS95 vs. PWS17
#X-squared = 6.582, df = 2, p-value = 0.03722
#bonferroni correction 0.05/12= 0.004166667
library(chisq.posthoc.test)
#Run post-hoc analysis
chisq.posthoc.test(t(X), method = "bonferroni")
# Dimension     Value       1991       1996       2007       2017
#1    Group1 Residuals -0.2299118 -0.7816124 -0.2095164  1.2728792
#2    Group1  p values  1.0000000  1.0000000  1.0000000  1.0000000
#3    Group2 Residuals  0.1518228  1.6660207 -1.2565640 -0.7840416
#4    Group2  p values  1.0000000  1.0000000  1.0000000  1.0000000
#5    Group3 Residuals  0.1268371 -1.4900885  2.4462947 -0.7966345
#6    Group3  p values  1.0000000  1.0000000  0.1732000  1.0000000

c20m<-melt(ch20_summary, id.vars="year")
ggplot(c20m, aes(x=factor(year), y=value, fill=variable))+
    geom_bar(stat="identity", width=0.5, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("Year")+ggtitle("PWS Chr20")
ggsave("../Output/PCA/PWS_ch20_prop_indivi_in3groups.png", width = 6, height = 4, dpi=150)

4.1.3 Calcualte Fst/Dxy between Groups across years within chr20

# read chr20 from the 'PWSonly' file
# Subset VCF by chr20 
#bcftools view  /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz --regions chr20 > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf


pws <- readData("../Data/new_vcf/PWSonly/PWSonly_chr20/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop=="PWS",]

#assign groups
pops$group<-"Group1"
pops$group[pops$Sample %in% gp2$Sample]<-"Group2"
pops$group[pops$Sample %in% gp3$Sample]<-"Group3"
populations <- split(pops$Sample, pops$group)
pws<-set.populations(pws, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr<-chrsize$V3[chrsize$V1=="chr20"]

# make a sliding window dataset
pws_sw <- sliding.window.transform(pws, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-pws_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
pws_sw <- diversity.stats(pws_sw, pi = TRUE)
pws_sw <- F_ST.stats(pws_sw, mode = "nucleotide")
# extract nucleotide diversity and correct for window size
nd <- pws_sw@nuc.diversity.within/50000
# make group name vector and rename the columns
groupnames <- sort(unique(pops$group))
colnames(nd) <- paste0(groupnames, "_pi")
# extract fst values
fst <- t(pws_sw@nuc.F_ST.pairwise)
# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(pws_sw, between = T)[[2]]/50000
# set the column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
pws_data <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(pws_data,"../Output/PCA/PWSonly_chr20_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1: nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-pws_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr20 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr,1 ))
        ggsave(paste0("../Output/PCA/PWSonly_Diversity_stats_chr20_",pop1," vs.", pop2,".png"), width = 9, height = 4, dpi=150)
    }

• What separates PWS groups are not the inversion, but the end of the choromsome (>21.8Mb)

4.1.4 Compare the heterozygosity of the region of interest (region 2)

# 1 divide the vcf into 3 groups -create the sample list for each group
write.table(gp1$Sample, "../Data/new_vcf/PWSonly/pwsch20_group1.txt", quote = F, row.names = F, col.names = F)
write.table(gp2$Sample, "../Data/new_vcf/PWSonly/pwsch20_group2.txt", quote = F, row.names = F, col.names = F)
write.table(gp3$Sample, "../Data/new_vcf/PWSonly/pwsch20_group3.txt", quote = F, row.names = F, col.names = F)
#Calculate heterozygosity per window using bcftools 
# 1. subset VCF by chr20 (het_stats_PWS.ch20.sh)
bcftools view  /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz --regions chr20 > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf
bgzip /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf
bcftools index /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf.gz

#2. subset by groups (This process can be done in R to group individuals)
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/pwsch20_group1.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group1_maf05.vcf.gz 
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/pwsch20_group2.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group2_maf05.vcf.gz 
bcftools view -Oz -S /home/ktist/ph/data/new_vcf/MD7000/population/pwsch20_group3.txt --threads 16 /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf.gz > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group3_maf05.vcf.gz 

bcftools index /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group3_maf05.vcf.gz 
bcftools index /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group2_maf05.vcf.gz 
bcftools index /home/ktist/ph/data/new_vcf/MD7000/PWSonly_chr20_group1_maf05.vcf.gz 

#3. Run het_stats20group1.sh to calculate het in windows
#4. cat all windows in to one file
d /home/ktist/ph/data/new_vcf/MD7000/population/ch20group1/
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > pws_ch20_group1_statsFile
cd /home/ktist/ph/data/new_vcf/MD7000/population/ch20group2/
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > pws_ch20_group2_statsFile
cd /home/ktist/ph/data/new_vcf/MD7000/population/ch20group3/
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > pws_ch20_group3_statsFile

4.1.5 Process the stats file to calculate Ho and He

# Calculate Ho and He from bcftools stats output files (stats from PWSonly files)
sfiles<-list.files("../Data/new_vcf/PWSonly/", pattern=paste0("_ch20_group\\d_statsFile"))


ho<- data.frame()
for (i in 1:length(sfiles)){
    df<-read.table(paste0("../Data/new_vcf/PWSonly/", sfiles[i]), sep="\t", header=F)
    pname<-paste0("group",i)
    df<-df[,c(3:10, 14:15)]
    colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
    df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    
    df$He<-2*df$p*df$q
    df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
    
    df$Group<-paste0("Group",i)
    ho<-rbind(df,ho)
}
Ho<-aggregate(ho[,"Ho"], by=list(ho$window_no,ho$Group), mean )
He<-aggregate(ho[,"He"], by=list(ho$window_no,ho$Group), mean )
het<-cbind(Ho, He$x)
colnames(het)<-c("window_id","Group","Ho","He")
write.csv(het,paste0("../Output/Stats_window/PWSonly_chr20_Hetero_bygroup_maf05.csv"))
    
het$window<-as.integer(gsub(paste0("pws_ch20_group\\d_maf05_stats_"),'',het$window_id))
het$loc<-"region1"
het$loc[het$window>215]<-"region2"
    
groupHo<-aggregate(het[,"Ho"], by=list(het$Group, het$loc), mean , na.rm=T)
colnames(groupHo)<-c("Group","Region","Ho")
write.csv(groupHo, "../Output/Stats_window/PWSonly_chr20_Hetero_group_summary.csv")

4.1.6 Compare Heterozygosity levels among groups and between regions

#Create a figure
gcols<-c("#FB687B","#48ABE3","#75BA76")
ggplot()+
    geom_boxplot(data=het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=groupHo, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')+ggtitle("Chr20")
ggsave("../Output/PCA/PWS_Chr20_Ho.in.tworegions.png", width = 6, height = 4, dpi=300)

4.1.7 Look at the overlap of individuals in Group3/Group2 among Chr20, Chr15 and Chr8 (PWSonly)

#ch15 adn ch8 groupings are the same for PWSonly and PWS+other pops
c15<-read.csv("../Output/PCA/chr15_PCAgroups.csv", row.names = 1)
c15<-c15[c15$pop=="PWS",]
c8<-read.csv("../Output/PCA/PWSonly_with.groups_pca_chr8.csv", row.names = 1)

c15g3<-c15$Sample[c15$Group=="Group3"]
c8g3<-c8$Sample[c8$group=="Group3"]
c20g3<-c20$Sample[c20$group=="Group3"]
x<-list(chr8=c8g3,chr15=c15g3, chr20=c20g3)
p3<-ggvenn(x, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

c15g2<-c15$Sample[c15$Group=="Group2"]
c8g2<-c8$Sample[c8$group=="Group2"]
c20g2<-c20$Sample[c20$group=="Group2"]
x2<-list(chr8=c8g2,chr15=c15g2, chr20=c20g2)
p2<-ggvenn(x2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")

venn<-ggdraw()+
        draw_plot(p2,x=0,y=0,width=0.5,height=1)+
        draw_plot(p3,0.5,0,0.5,1)+
        draw_plot_label("PWS", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch8.15.20.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   


4.2 Chr20 groups across all populations

4.2.1 Compare 3 groups separated by PC1 (‘Inversion Gropus’)

#proportion of year in each group
chr20<-read.csv("../Output/chr/DP7000/chr20_PCAgroups.csv")
#group3 is group1 (1==the most majority in new grouping)
chr20$Group[chr20$Group==1]<-"Group3"
chr20$Group[chr20$Group==3]<-"Group1"
chr20$Group[chr20$Group==2]<-"Group2"

chr20_sum<-data.frame(table(chr20$Group,chr20$yr.pop))
colnames(chr20_sum)<-c("Group","yr.pop","Freq")

chr20_sum$yr.pop<-factor(chr20_sum$yr.pop, levels=c("PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))
ggplot(chr20_sum, aes(x=yr.pop, y=Freq, fill=Group))+
    geom_bar(stat="identity", width=0.8, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("")+ggtitle("Chr20")
ggsave("../Output/PCA/Ch20_prop_indivi_in3groups.png", width = 7, height = 4, dpi=300)

4.2.2 Calcualte Fst between Groups within chr20 for all pops (except TB)

ph <- readData("../Data/new_vcf/ch20/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop!="TB",]

#assign groups
pops$group<-"Group1"
pops$group[pops$Sample %in% chr20$Sample[chr20$Group=="Group2"]]<-"Group2"
pops$group[pops$Sample %in% chr20$Sample[chr20$Group=="Group3"]] <-"Group3"
populations <- split(pops$Sample, pops$group)
ph<-set.populations(ph, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr<-chrsize$V3[chrsize$V1=="chr20"]

# make a sliding window dataset
ph_sw <- sliding.window.transform(ph, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-ph_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
ph_sw <- diversity.stats(ph_sw, pi = TRUE)
ph_sw <- F_ST.stats(ph_sw, mode = "nucleotide")
# extract nucleotide diversity and correct for window size
nd <- ph_sw@nuc.diversity.within/50000
# make group name vector and rename the columns
groupnames <- sort(unique(pops$group))
colnames(nd) <- paste0(groupnames, "_pi")
# extract fst values
fst <- t(ph_sw@nuc.F_ST.pairwise)
# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(ph_sw, between = T)[[2]]/50000
# set the column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
ph_data <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(ph_data,"../Output/PCA/PH_noTB_chr20_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1:nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-ph_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr20 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr,1 ))
        ggsave(paste0("../Output/PCA/Ch20_Diversity_stats_",pop1,".vs.", pop2,".png"), width = 9, height = 4, dpi=150)
    }

4.2.3 How the grouping overlap between ‘all-pop’ vs. ‘PWSonly’?

# c20= PWSonly chr20 +allpops

chr20$Sample[chr20$Group=="Group3"&chr20$pop=="PWS"] #1 sample ('0590_PWS91')
g2_a<-chr20$Sample[chr20$Group=="Group2"&chr20$pop=="PWS"] #25 samples
#[1] "0367_PWS07" "0412_PWS07" "0560_PWS07" "1146_PWS07" "1148_PWS07" "1150_PWS07" "0475_PWS17" "0652_PWS17"
#[9] "0956_PWS17" "0958_PWS17" "0978_PWS17" "0984_PWS17" "1034_PWS17" "1036_PWS17" "1037_PWS17" "0564_PWS91"
#[17] "0671_PWS91" "0700_PWS91" "1203_PWS91" "1207_PWS91" "0755_PWS96" "0757_PWS96" "0961_PWS96" "1079_PWS96"
#[25] "1116_PWS96"
g3_p<-c20$Sample[c20$group=="Group3"] #23 individuals
g2_p<-c20$Sample[c20$group=="Group2"] #110 samples

#Do pws-group3 samples belong to all-group3?
#
g3_p[g3_p %in% g2_a] #only 3 samples from Group3_PWS belogn to group2-All
#"0956_PWS17" "0652_PWS17" "0700_PWS91"
g2_p[g2_p %in% g2_a] #14 samples from Group2_PWS belong to Group2_All
#[1] "0367_PWS07" "0560_PWS07" "1146_PWS07" "1148_PWS07" "0475_PWS17" "0958_PWS17" "0984_PWS17" "1036_PWS17"
#[9] "1037_PWS17" "0564_PWS91" "0671_PWS91" "0755_PWS96" "0961_PWS96" "1116_PWS96"


#different grouping (vertical(PC2) vs. horizontal (PC1) clustering)
#Create new groups separated along PC2 ->call 'clusters'

pca20<-read.csv("../Output/PCA/noTB_pca_chr20.csv")
c3.1<-pca20[pca20$PC2>0.06&pca20$PC1<0.05,] #46
c3.2<-pca20[pca20$PC2>0.01&pca20$PC1>0.0509,] #23
c3.3<-pca20[pca20$PC2>(-0.03)&pca20$PC1>0.12,] #19 CA inversion

c2.1<-pca20[pca20$PC2>(-0.011)&pca20$PC2<0.06&pca20$PC1>(-0.02)&pca20$PC1<0.01,] #216
c2.2<-pca20[pca20$PC2>(-0.05)&pca20$PC2<0.035&pca20$PC1>(0.015)&pca20$PC1<0.079,] #37
c2.3<-pca20[pca20$PC2>(-0.1)&pca20$PC2<(-0.07)&pca20$PC1>(0.1),] #12

c1.1<-pca20[pca20$PC2<(-0.011)&pca20$PC1<0.0,] #241
c1.2<-pca20[pca20$PC2<(-0.05)&pca20$PC2<0.035&pca20$PC1>0&pca20$PC1<0.05,] #26
c1.3<-pca20[pca20$PC2<(-0.1)&pca20$PC1>(0.1),] #1

pca20$Cluster<-1
pca20$Subcluster<-1.1
pca20$Subcluster[pca20$Sample %in% c1.2$Sample]<-1.2
pca20$Subcluster[pca20$Sample %in% c1.3$Sample]<-1.3

pca20$Cluster[pca20$Sample %in% c(c2.1$Sample,c2.2$Sample,c2.3$Sample)]<-2
pca20$Subcluster[pca20$Sample %in% c2.1$Sample]<-2.1
pca20$Subcluster[pca20$Sample %in% c2.2$Sample]<-2.2
pca20$Subcluster[pca20$Sample %in% c2.3$Sample]<-2.3

pca20$Cluster[pca20$Sample %in% c(c3.1$Sample,c3.2$Sample,c3.3$Sample)]<-3
pca20$Subcluster[pca20$Sample %in% c3.1$Sample]<-3.1
pca20$Subcluster[pca20$Sample %in% c3.2$Sample]<-3.2
pca20$Subcluster[pca20$Sample %in% c3.3$Sample]<-3.3

#pca20$Grouping<-1
#pca20$Group[pca20$Sample %in% c(c1.2$Sample,c2.2$Sample,c3.2$Sample)]<-2
#pca20$Group[pca20$Sample %in% c(c1.3$Sample,c2.3$Sample,c3.3$Sample)]<-2

pca20<-merge(pca20, chr20[,c("Sample","Group","yr.pop")], by="Sample")
write.csv(pca20,"../Output/PCA/chr20_group_cluster.csv", row.names=F)

#create colors based on cluster
ccols<-c("#fd8d3c","#fdbe85","#fdd49e","#3182bd","#6baed6","#9ecae1","#df65b0","#c994c7","#d4b9da")


ggplot()+
        geom_point(data = pca20, aes(x = PC1, y = PC2, color = factor(Subcluster), fill = factor(Subcluster), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,3,21), name="Year")+
        scale_fill_manual(values=paste0(ccols,"66"), guide="none")+
        scale_color_manual(values=ccols, name="Population")+
        theme_bw()+theme(legend.title = element_blank())+
        stat_ellipse(data=pca20, aes(x=PC1, y=PC2, group=factor(Subcluster)), color="gray50", size=0.2,level=0.999)
ggsave("../Output/PCA/Chr20_Cluster.subcluster.png", width = 6, height = 4.5, dpi=300)

4.2.4 Look at Fst between Clusters (separted by PC2) within chr20 for all pops

ph <- readData("../Data/new_vcf/ch20/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop!="TB",]

#assign groups
pops$group<-"Cluster1"
pops$group[pops$Sample %in% pca20$Sample[pca20$Cluster==2]] <-"Cluster2"
pops$group[pops$Sample %in% pca20$Sample[pca20$Cluster==3]] <-"Cluster3"
populations <- split(pops$Sample, pops$group)
ph<-set.populations(ph, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr<-chrsize$V3[chrsize$V1=="chr20"]

# make a sliding window dataset
ph_sw <- sliding.window.transform(ph, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-ph_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
ph_sw <- diversity.stats(ph_sw, pi = TRUE)
ph_sw <- F_ST.stats(ph_sw, mode = "nucleotide")
# extract nucleotide diversity and correct for window size
nd <- ph_sw@nuc.diversity.within/50000
# make group name vector and rename the columns
groupnames <- sort(unique(pops$group))
colnames(nd) <- paste0(groupnames, "_pi")
# extract fst values
fst <- t(ph_sw@nuc.F_ST.pairwise)
# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(ph_sw, between = T)[[2]]/50000
# set the column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
ph_data <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(ph_data,"../Output/PCA/PH_noTB_chr20_Clusters_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1:nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-ph_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr20 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr,1 ))
        ggsave(paste0("../Output/PCA/Ch20_Diversity_stats_",pop1,".vs.", pop2,".png"), width = 9, height = 4, dpi=150)
}

4.2.5 Check PWSonly groups matches cluster nubmers

pws20<-pca20[pca20$pop=="PWS",]
pws20<-merge(pws20[,c(1:5,12:13,15)], c20[,c("Sample","group")], by="Sample")
pws20$Group<-as.integer(gsub("Group", '',pws20$group))
pws20$match<-ifelse(pws20$Cluster==pws20$Group, 0, 1)
pws20[pws20$match==1,]
ph <- readData("../Data/new_vcf/ch20/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop!="TB",]
#assign groups
pops$group<-"Cluster1.1"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==1.2]] <-"Cluster1.2"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==1.3]] <-"Cluster2.3"#group with cluster2.3 since 1 sample
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==2.1]] <-"Cluster2.1"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==2.2]] <-"Cluster2.2"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==2.3]] <-"Cluster2.3"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==3.1]] <-"Cluster3.1"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==3.2]] <-"Cluster3.2"
pops$group[pops$Sample %in% pca20$Sample[pca20$Subcluster==3.3]] <-"Cluster3.3"

populations <- split(pops$Sample, pops$group)
ph<-set.populations(ph, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr<-chrsize$V3[chrsize$V1=="chr20"]

# make a sliding window dataset
ph_sw <- sliding.window.transform(ph, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-ph_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
ph_sw <- diversity.stats(ph_sw, pi = TRUE)
ph_sw <- F_ST.stats(ph_sw, mode = "nucleotide")
groupnames <- sort(unique(pops$group))
fst <- t(ph_sw@nuc.F_ST.pairwise)
dxy <- get.diversity(ph_sw, between = T)[[2]]/50000
# set the column names 
x <- colnames(fst)
for (i in 1:length(x)){
    x <- sub(paste0("pop",i), groupnames[i], x)
}
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
ph_data2 <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(ph_data2,"../Output/PCA/PH_noTB_chr20_Subclusters_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1:nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-ph_data2[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2)) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr20 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr,1 ))
        ggsave(paste0("../Output/PCA/chr20/Ch20_Diversity_stats_",pop1,".vs.", pop2,".png"), width = 8, height = 2, dpi=150)
}

4.2.5.1 Subclusters within the Cluster are based on the inversion


4.2.5.2 between clusters are based on the region at the end of chromsome


4.2.6 Create a stacked bar-chart for clusters

pca20<-read.csv("../Output/PCA/chr20_group_cluster.csv")

pca20_sum<-data.frame(table(pca20$Subcluster,pca20$yr.pop))
colnames(pca20_sum)<-c("Cluster","yr.pop","Freq")
pca20_sum$headCluster<-substr(pca20_sum$Cluster, 1,1)

pca20_sum$yr.pop<-factor(pca20_sum$yr.pop, levels=c("PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))

#1. Groping only (not the inversion cluster)

chr20_cl<-data.frame(table(pca20$Cluster,pca20$yr.pop))
colnames(chr20_cl)<-c("Cluster","yr.pop","Freq")
chr20_cl$yr.pop<-factor(chr20_cl$yr.pop, levels=c("PWS91","PWS96","PWS07","PWS17","SS96","SS06","SS17","BC17","WA17","CA17"))
ggplot(chr20_cl, aes(x=yr.pop, y=Freq, fill=Cluster))+
    geom_bar(stat="identity", width=0.8, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("")+ggtitle("Chr20 Groping (non-inversion)")
ggsave("../Output/PCA/Ch20_prop_indivi_in3groups.nonInversion.png", width = 7, height = 4, dpi=300)


#create colors based on cluster
ccols<-c("#fd8d3c","#fdbe85","#fdd49e","#3182bd","#6baed6","#9ecae1","#df65b0","#c994c7","#d4b9da")

ggplot(pca20_sum, aes(x=yr.pop, y=Freq, fill=Cluster))+
    geom_bar(stat="identity", width=0.8, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=ccols)+xlab("")+ggtitle("Chr20")
ggsave("../Output/PCA/Ch20_prop_indivi_inClusters.png", width = 7, height = 4, dpi=300)



5 Chr4

5.1 PCA clusters into 3 groups for PWSonly, but not so clear when all populations are incldued

#proportion of year in each group
ch4<-read.csv("../Output/PCA/PWSonly_pca_chr4.csv")
gp1.1<-ch4[ch4$PC1>0.02,]
gp1.2<-ch4[ch4$PC1>(-0.02)&ch4$PC2<0,]
gp1.2<-gp1.2[!(gp1.2$Sample%in% gp1.1$Sample),]
gp1<-rbind(gp1.1, gp1.2)

gp3.1<-ch4[ch4$PC1<(-0.09)&ch4$PC2>(-0.06),]
gp3.2<-ch4[ch4$PC1<(-0.2)&ch4$PC2<(-0.1),]
gp3<-rbind(gp3.1,gp3.2)
gp2<-ch4[!(ch4$Sample %in% c(gp1$Sample, gp3$Sample)),  ]

table(gp1$year) #127
#1991 1996 2007 2017 
#  32   37   29   29  
table(gp2$year) #88
#1991 1996 2007 2017 
#  20   29   14   25   
table(gp3$year) #17
#1991 1996 2007 2017 
#   6    6    3    2  

gp1$group<-"Group1"
gp2$group<-"Group2"
gp3$group<-"Group3"
c4<-rbind(gp1,gp2,gp3)
write.csv(c4, "../Output/PCA/PWSonly_with.groups_pca_chr4.csv")

pcols<-c("#d7b5d8","#df65b0","#dd1c77","#980043")
ggplot()+
        geom_point(data = c4, aes(x = PC1, y = PC2, fill = factor(year), color = factor(year), shape = factor(year)), size = 3)+
        scale_shape_manual(values=c(23,25,3,21), guide="none")+
        scale_fill_manual(values=paste0(pcols,"99"), guide="none")+
        scale_color_manual(values=pcols[1:4])+
        xlab(paste("PC 1"))+
        ylab(paste("PC 2"))+
        theme_bw()+
        ggtitle("Chr4")+
        guides(shape = guide_legend(override.aes =c(23,25,3,21)), fill=guide_legend(override.aes =paste0(pcols,"99")))+theme(legend.title = element_blank())+
        stat_ellipse(data=c4, aes(x=PC1, y=PC2, group=group), color="gray50", size=0.2,level=0.997)+
         annotate("text", x=0.05, y=-0.2, label="Group 1")+
    annotate("text", x=-0.08, y=-0.2, label="Group 2")+
    annotate("text", x=-0.22, y=0.2, label="Group 3")
ggsave("../Output/PCA/PWSonly_Ch4_PCA_withGroups.png", width = 6, height = 4.5, dpi=300)
#TB is in 1 group for chr4

5.1.1 Create a grouping summary plot

#Create a summary
ch4_summary<-data.frame(year=c(1991,1996,2007,2017))
ch4_summary$Group1<-as.vector(table(gp1$year))
ch4_summary$Group2<-as.vector(table(gp2$year))
ch4_summary$Group3<-as.vector(table(gp3$year))

#quick chi-square test 
chisq.test(ch4_summary[,2:4])
#X-squared = 4.3902, df = 6, p-value = 0.624


c4m<-melt(ch4_summary, id.vars="year")
ggplot(c4m, aes(x=factor(year), y=value, fill=variable))+
    geom_bar(stat="identity", width=0.5, color="gray40",position = "fill")+
    theme_linedraw()+theme(legend.title = element_blank())+ylab("Proportion of individuals")+
    scale_fill_manual(values=c("#fbb4ae","#b3cde3","#ccebc5"))+xlab("Year")+ggtitle("PWS Chr4")
ggsave("../Output/PCA/PWS_ch4_prop_indivi_in3groups.png", width = 6, height = 4, dpi=150)

5.1.2 Calcualte Fst between Groups within chr4 (PWSonly)

# read chr4 from the 'PWSonly' file
# Subset VCF by chr20 
#bcftools view  /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz --regions chr20 > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf


pws <- readData("../Data/new_vcf/PWSonly/PWSonly_chr4/", format = "VCF", include.unknown = TRUE, FAST = TRUE)
pop_info<-read.csv("../Data/Sample_metadata_892pops.csv")
pops<-pop_info[pop_info$pop=="PWS",]

#assign groups
pops$group<-"Group1"
pops$group[pops$Sample %in% c4$Sample[c4$group=="Group2"]]<-"Group2"
pops$group[pops$Sample %in% c4$Sample[c4$group=="Group3"]]<-"Group3"
populations <- split(pops$Sample, pops$group)
pws<-set.populations(pws, populations, diploid = T)

# set the chromosome size
chrsize<-read.table("../Data/new_vcf/chr_sizes.bed")
chr<-chrsize$V3[chrsize$V1=="chr4"]

# make a sliding window dataset
pws_sw <- sliding.window.transform(pws, width = 50000, jump = 10000, type = 2)
# crate sliding window info
windows<-pws_sw@region.names
windows<-gsub(" ","", windows)
windows<-gsub(":","",windows)
window_start<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[1]))
window_stop<-as.integer(sapply(windows, function(x) unlist(strsplit(x, "-"))[2]))
window<-data.frame(start = window_start, stop = window_stop, 
                      mid = window_start + (window_stop-window_start)/2)

#calculate diversity stats
pws_sw <- diversity.stats(pws_sw, pi = TRUE)
pws_sw <- F_ST.stats(pws_sw, mode = "nucleotide")
# extract nucleotide diversity and correct for window size
nd <- pws_sw@nuc.diversity.within/50000
# make group name vector and rename the columns
groupnames <- sort(unique(pops$group))
colnames(nd) <- paste0(groupnames, "_pi")
# extract fst values
fst <- t(pws_sw@nuc.F_ST.pairwise)
# extract dxy - pairwise absolute nucleotide diversity
dxy <- get.diversity(pws_sw, between = T)[[2]]/50000
# set the column names 
x <- colnames(fst)
x <- sub("pop1", groupnames[1], x)
x <- sub("pop2", groupnames[2], x)
x <- sub("pop3", groupnames[3], x)
x <- sub("/", "_", x)

colnames(fst)<-paste0("fst_",x)
colnames(dxy)<-paste0("dxy_",x)

#combine all data
pws_data <- as_tibble(data.frame(window, nd, fst, dxy))
write.csv(pws_data,"../Output/PCA/PWSonly_chr4_popgenome_stats.csv")

comb<-combn(groupnames, 2)
comb<-t(comb)
for (i in 1: nrow(comb)){
        pop1<-comb[i,1]
        pop2<-comb[i,2]
        dt<-pws_data[, c("mid", paste0("fst_", pop1,"_",pop2),paste0("dxy_",pop1,"_",pop2), paste0(pop1,"_pi"),paste0(pop2,"_pi")) ]
        colnames(dt)[2:3]<-c("Fst","Dxy")
    
        dt_g<-gather(dt, -mid, key = "stat", value = "value")
        dt_g$stat<-factor(dt_g$stat, levels=c("Fst","Dxy",colnames(dt)[4], colnames(dt)[5]))
        ggplot(dt_g, aes(mid/10^6, value, colour = stat)) + geom_line()+
            facet_grid(stat~., scales = "free_y")+
            xlab("Position (Mb)")+ylab('')+
            theme_light() + theme(legend.position = "none")+ggtitle(paste0("Chr4 ",pop1," vs.", pop2))+
            scale_x_continuous(minor_breaks = seq(1, chr,1 ))
        ggsave(paste0("../Output/PCA/PWSonly_Diversity_stats_chr4_",pop1," vs.", pop2,".png"), width = 9, height = 4, dpi=150)
    }

  • PWS groups are separated by theend of the choromsome (>27.3Mb)

5.1.3 Compare the heterozygosity of the region of interest (region 2 >27.3Mb)

#Calculate heterozygosity per window using bcftools 
# 1. subset VCF by chr20 (het_stats_PWS.ch20.sh)
bcftools view  /home/ktist/ph/data/new_vcf/MD7000/PWSonly_NS0.5_maf05.vcf.gz --regions chr4 > /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch20_maf05.vcf
bgzip /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch4_maf05.vcf
bcftools index /home/ktist/ph/data/new_vcf/MD7000/PWSonly_ch4_maf05.vcf.gz
#2. Run het_stats4_PWS.sh to calculate het in windows
#3. Change the files to tab-delimited and cat them
for f in *; do sed -i "s/$/\t$f/" $f; done 
cat $(ls -t) > PWSonly_ch4_maf05_statsFile

5.1.4 Process the stats file to obtain Ho and He

# Calculate Ho and He from bcftools stats output files (stats from PWSonly files)
df<-read.table("../Data/new_vcf/PWSonly/PWSonly_ch4_maf05_statsFile",sep="\t", header=F)
df<-df[,c(3:10, 14:15)]
colnames(df)<-c("Sample","nRefHom","nNonRefHom","nHets", "nTransitions", "nTransversions","nIndels","average depth","nMissing","window_no")
df$p<-(2*df$nRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
df$q<-(2*df$nNonRefHom+df$nHets)/(rowSums(df[,c("nRefHom","nNonRefHom","nHets")])*2)
    
df$He<-2*df$p*df$q
df$Ho<-df$nHets/rowSums(df[,c("nRefHom","nNonRefHom","nHets")])
ho<-merge(df, c4[,c("Sample","pop","year","group")], by="Sample")
years<-c(1991,1996,2007,2017)

Ho<-aggregate(ho[,"Ho"], by=list(ho$window_no,ho$group, ho$year), mean, na.rm=T )
He<-aggregate(ho[,"He"], by=list(ho$window_no,ho$group, ho$year), mean, na.rm=T )
het<-cbind(Ho, He$x)
colnames(het)<-c("window_id","Group","year","Ho","He")
write.csv(het,paste0("../Output/Stats_window/PWSonly_chr4_Hetero_byGroup.year_maf05.csv"))
    
het$window<-as.integer(gsub(paste0("PWS_ch4_stats_"),'',het$window_id))
het$loc<-"region1"
het$loc[het$window>273]<-"region2"
    
groupHo<-aggregate(het[,"Ho"], by=list(het$Group, het$loc, het$year), mean , na.rm=T)
colnames(groupHo)<-c("Group","Region","Year","Ho")
write.csv(groupHo, "../Output/Stats_window/PWSonly_chr4_Hetero_group_summary.csv")

5.1.5 Compare Heterozygosity levels among groups and between regions

#Create a figure
gcols<-c("#FB687B","#48ABE3","#75BA76")

ggplot()+
    geom_boxplot(data=het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=groupHo, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    facet_wrap(~year)+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')
ggsave("../Output/PCA/PWS_Chr15_Ho.in.tworegions_byYears.png", width = 8, height = 7, dpi=300)

#all years together
groupHo2<-aggregate(het[,"Ho"], by=list(het$Group, het$loc), mean , na.rm=T)
colnames(groupHo2)<-c("Group","Region","Ho")
ggplot()+
    geom_boxplot(data=het,aes(x=loc, y=Ho, color=Group, fill=Group), position=position_dodge(width =0.8),outlier.alpha = 0.6, outlier.size = 1,width=0.7)+
    geom_point(data=groupHo2, aes(x=Region, y=Ho, color=Group),position=position_dodge(width =0.8))+
    theme_minimal()+
    theme(panel.grid.major.x = element_blank())+
    geom_vline(xintercept = c(1.5), color="gray70",size=0.3)+
    scale_color_manual(values=gcols)+
    scale_fill_manual(values=paste0(gcols, "66"))+xlab('')+ggtitle("Chr20")
ggsave("../Output/PCA/PWS_Chr20_Ho.in.tworegions.png", width = 6, height = 4, dpi=300)

5.2 Look at the overlap of individuals

5.2.1 Beween Group3 & Group2 among Chr20, Chr15, Chr8, and Chr4 (PWSonly)

#ch15 adn ch8 groupings are the same for PWSonly and PWS+other pops
c15<-read.csv("../Output/PCA/chr15_PCAgroups.csv", row.names = 1)
c15<-c15[c15$pop=="PWS",]
c8<-read.csv("../Output/PCA/PWSonly_with.groups_pca_chr8.csv", row.names = 1)

c15g3<-c15$Sample[c15$Group=="Group3"]
c8g3<-c8$Sample[c8$group=="Group3"]
c20g3<-c20$Sample[c20$group=="Group3"]
c4g3<-c4$Sample[c4$group=="Group3"]

x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20g3)
p3<-ggvenn(x, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

c15g2<-c15$Sample[c15$Group=="Group2"]
c8g2<-c8$Sample[c8$group=="Group2"]
c20g2<-c20$Sample[c20$group=="Group2"]
c4g2<-c4$Sample[c4$group=="Group2"]

x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20g2)
p2<-ggvenn(x2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")

c15g1<-c15$Sample[c15$Group=="Group1"]
c8g1<-c8$Sample[c8$group=="Group1"]
c20g1<-c20$Sample[c20$group=="Group1"]
c4g1<-c4$Sample[c4$group=="Group1"]
x1<-list(chr4=c4g1, chr8=c8g1,chr15=c15g1, chr20=c20g1)
p1<-ggvenn(x1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.8.15.20.group_overlap.png"), plot = venn,base_width = 10, base_height = 5, dpi=300)   

5.2.2 Pairwise comparison

5.2.2.1 chr4 vs. chr8

#x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20g3)
#x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20g2)
x.1<-list(chr4=c4g3, chr8=c8g3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

x2.2<-list(cchr4=c4g2, chr8=c8g2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.1<-list(chr4=c4g1, chr8=c8g1)
p1<-ggvenn(x1.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr4 vs. chr8", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.8.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

5.2.2.2 chr4 vs. chr15

#x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20g3)
#x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20g2)
x.1<-list(chr4=c4g3, chr15=c15g3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")
x2.2<-list(chr4=c4g2, chr15=c15g2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.1<-list(chr4=c4g1, chr15=c15g1)
p1<-ggvenn(x1.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr4 vs. chr15", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.15.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

5.2.2.3 chr4 vs. chr20(end-groups)

x.1<-list(chr4=c4g3,chr20=c20g3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")
x2.2<-list(chr4=c4g2, chr20=c20g2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.1<-list(chr4=c4g1, chr20=c20g1)
p1<-ggvenn(x1.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr4 vs. chr20(end)", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.20.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

5.2.2.4 chr15 vs. chr20(end)

x.1<-list(chr15=c15g3, chr20=c20g3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

x2.2<-list(chr15=c15g2, chr20=c20g2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.1<-list(chr15=c15g1,chr20=c20g1)
p1<-ggvenn(x1.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr15 vs. chr20", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch15.20.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

5.2.2.5 chr8 vs. chr20(end)

#x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20g3)
#x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20g2)
x.1<-list(chr8=c8g3, chr20=c20g3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")
x2.2<-list(chr8=c8g2,chr20=c20g2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.1<-list(chr8=c8g1,chr20=c20g1)
p1<-ggvenn(x1.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr8 vs. chr20(end)", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch8.20end.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

5.2.3 chr20 grouping with inversion clusters

#ch15 adn ch8 groupings are the same for PWSonly and PWS+other pops
c20c3<-pca20$Sample[pca20$Group=="Group3"]
x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20c3)
p3<-ggvenn(x, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")

c20c2<-pca20$Sample[pca20$Group=="Group2"]
x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20c2)
p2<-ggvenn(x2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")

c20c1<-pca20$Sample[pca20$Group=="Group1"]
x1<-list(chr4=c4g1, chr8=c8g1,chr15=c15g1, chr20=c20c1)
p1<-ggvenn(x1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
        draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS Chr20 inversion cluster", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.8.15.group+20cluster_overlap.png"), plot = venn,base_width = 10, base_height = 5, dpi=300)   

5.2.3.1 chr4 vs. chr20_inv

#x<-list(chr4=c4g3, chr8=c8g3,chr15=c15g3, chr20=c20g3)
#x2<-list(chr4=c4g2, chr8=c8g2,chr15=c15g2, chr20=c20g2)
x.1<-list(chr4=c4g3, chr20=c20c3)
p3<-ggvenn(x.1, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group3")
x2.2<-list(chr4=c4g2, chr20=c20c2)
p2<-ggvenn(x2.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group2")
x1.2<-list(chr4=c4g1, chr20=c20c1)
p1<-ggvenn(x1.2, fill_color = cols, stroke_size = 0.5, set_name_size = 4,text_size=3)+ggtitle("Group1")

venn<-ggdraw()+
       draw_plot(p1,x=0,y=0,width=0.33,height=1)+
        draw_plot(p2,x=0.33,y=0,width=0.33,height=1)+
        draw_plot(p3,0.66,0,0.33,1)+
        draw_plot_label("PWS chr4 vs. chr20(inv)", x=-0.01, y=0.95, size = 15)
save_plot(filename =paste0("../Output/PCA/PWS_ch4.20inv.group_overlap.png"), plot = venn,base_width = 7, base_height = 5, dpi=300)   

LS0tCnRpdGxlOiAiUENBbmdzZCIKb3V0cHV0IjogaHRtbF9ub3RlYm9vawpvdXRwdXQ6CiAgaHRtbF9ub3RlYm9vazoKICAgICAgdG9jOiB0cnVlIAogICAgICB0b2NfZmxvYXQ6IHRydWUKICAgICAgbnVtYmVyX3NlY3Rpb25zOiB0cnVlCiAgICAgIHRoZW1lOiBsdW1lbgogICAgICBoaWdobGlnaHQ6IHRhbmdvCiAgICAgIGNvZGVfZm9sZGluZzogaGlkZQogICAgICBkZl9wcmludDogcGFnZWQKLS0tCiMgUnVuIFBDQW5zZ2QgZm9yIFBXUyBwb3B1bGF0aW9ucyAKVXNpbmcgdGhlICdQV1Nvbmx5JyBzaXRlcyAofjc3MGsgc25wcykgClJ1bm5pbmcgUENBbmdzZCByZXF1aXJlcyBzZXZlcmFsIHN0ZXBzCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGluY2x1ZGU9RkFMU0V9CnNvdXJjZSgiLi4vUnNjcmlwdHMvQmFzZVNjcmlwdHMuUiIpCmxpYnJhcnkoZ3JpZEV4dHJhKQpsaWJyYXJ5KGdnZm9yY2UpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KFBvcEdlbm9tZSkKbGlicmFyeShkcGx5cikKbGlicmFyeShjb3dwbG90KQpsaWJyYXJ5KGdndmVubikKbGlicmFyeShrbml0cikKbGlicmFyeShrYWJsZUV4dHJhKQpgYGAKCiMjIFN0ZXBzCgojIyMgUHJ1bmUgU05QczogVXNpbmcgUGxpbmsgdG8gcHJ1bmUgaGlnaGx5IGxpbmtlZCBzbnBzICAKKiBOZWVkIHRvIHJlZm9ybWF0IHRoZSBvdXRwdXQgKHh4eC5wcnVuZS5pbikgZmlsZSB0byBzdWJzZXQgYSB2Y2YgZmlsZSAocmF0ZWhyIHRoYW4gdXNpbmcgaXQgZm9yICBwcnVpbmcgYSBwZWQvYmVkIGZpbGUpIApgYGB7YmFzaCBldmFsPUZBTFNFLCBlY2hvPVRSVUV9CiNmaXJzdCBjcmVhdGUgcGVkL2JlZCBmaWxlcyB3aXRoIGFkZGluZyB2YXJpYW50IGlkCm1vZHVsZSBsb2FkIHBsaW5rCnBsaW5rIC0tdmNmIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogLS1zZXQtbWlzc2luZy12YXItaWRzIEA6I1twaF1cXCRyLFxcJGEgLS1tYWtlLWJlZCAtLW91dCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvUFdTb25seV9OUzAuNV9tYWYwNQpwbGluayAtLWJmaWxlIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9QV1Nvbmx5X05TMC41X21hZjA1IC0tcmVjb2RlIC0tdGFiIC0tb3V0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9QV1Nvbmx5X05TMC41X21hZjA1CgojZmluZCBoaWdobHkgY29ycmVsYXRlZCBzaXRlcyBmb3IgcHJ1bmluZwpwbGluayAtLWZpbGUgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1BXU29ubHlfTlMwLjVfbWFmMDUgLS1pbmRlcC1wYWlyd2lzZSA3NSdrYicgNSAwLjUgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1BXU29ubHlfTlMwLjVfbWFmMDVfNzVfNV8wLjUKCiM1MGtiIGRvZXMgbm90IG1ha2UgbXVjaCBkaWZmZXJlbmNlCnBsaW5rIC0tZmlsZSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvUFdTb25seV9OUzAuNV9tYWYwNSAtLWluZGVwLXBhaXJ3aXNlIDUwJ2tiJyA1IDAuNSAtLW91dCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvUFdTb25seV9OUzAuNV9tYWYwNV81MF81XzAuNQojIFNlZSBjb21wYXJpc29uIHJlc3VsdHMgaW4gICAgIERhdGEvUENBbmdzZC9wcnVuaW5nX3BhcmFtZXRlcl9kaWZmZXJlbmNlLnR4dAoKI1JlZm9ybWF0IHBydW4uaW4gZmlsZSB3aXRoIHJ1bm5pbmcgdGhlIHJlZm9ybWF0X3BydW5pbi5SClIKc291cmNlKCJyZWZvcm1hdF9wcnVuaW4uUiIpCnJlZm9ybWF0X3BydW5pbigicGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1BXU29ubHlfTlMwLjVfbWFmMDVfNzVfNV8wLjUucHJ1bmUuaW4iKQpxdWl0KCkKYGBgCgojIyMgVXNpbmcgYmNmdG9vbHMgdG8gc3Vic2V0IHRoZSBWQ0YgZmlsZSB1c2luZyBwcnVuZS5pbiBmaWxlCgojIyMgQ29udmVydCBWQ0YgdG8gdGhlIGJlYWdsZSBmb3JtYXQgYW5kIHJ1biBQQ0Fuc2dkCgpgYGB7YmFzaCBldmFsPUZBTFNFLCBlY2hvPVRSVUV9CiNjcmVhdGUgdmNmIGZpbGVzIHdpdGggb25seSBwcnVuZS5pbiBzaXRlcwojaW5kZXggdGhlIHZjZiBmaXJzdApiY2Z0b29scyBpbmRleCBob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3oKCmJjZnRvb2xzIHZpZXcgLVIgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wbGlua2ZpbGVzL1BXU29ubHlfTlMwLjVfbWFmMDVfNzVfNV8wLjUucHJ1bmUuaW4uc2l0ZXMudHh0IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvUFdTb25seV9tYWYwNV9wcnVuZWQudmNmCmJnemlwIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcGxpbmtmaWxlcy9QV1Nvbmx5X21hZjA1X3BydW5lZC52Y2YKCiNDcmVhdGUgYmVhZ2xlIGZpbGVzIChjcmVhdGVfYmVhZ2xlX1BXUy5zaCkKI2UuZy4KdmNmdG9vbHMgLS1nenZjZiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BsaW5rZmlsZXMvUFdTb25seV9tYWYwNV9wcnVuZWQudmNmLmd6IC0tY2hyIGNocjEgLS1vdXQgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9iZWFnbGUvUFdTb25seV9wcnVuZWRfYzEgLS1CRUFHTEUtUEwgCgpnemlwIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvYmVhZ2xlL1BXU29ubHlfcHJ1bmVkX2MxLkJFQUdMRS5QTCAKCiNSdW4gUENBbmdzZCAocGNhbmdzZF9wd3Muc2gpCiNlLmcuIApweXRob24gL2hvbWUvamFtY2dpcnIvYXBwcy9wY2FuZ3NkL3BjYW5nc2QucHkgLWJlYWdsZSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL2JlYWdsZS9QV1Nvbmx5X3BydW5lZF9jMS5CRUFHTEUuUEwuZ3ogLW8gL2hvbWUva3Rpc3QvcGgvZGF0YS9hbmdzZC9QQ0FuZ3NkL1BXU29ubHlfbWFmMDVfY2hyMSAtdGhyZWFkcyAxNiAKCmBgYAoKCiMjIFJlc3VsdHMgb2YgUENBbmdzZCAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BfaW5mbzwtcG9wX2luZm9bLGMoIlNhbXBsZSIsIlBvcHVsYXRpb24uWWVhciIsInBvcCIsIlllYXIuQ29sbGVjdGVkIildCmNvbG5hbWVzKHBvcF9pbmZvKVs0XTwtInllYXIiCnBvcHM8LXBvcF9pbmZvW3BvcF9pbmZvJHBvcD09IlBXUyIsXQoKcGNvbHM8LWMoIiNkN2I1ZDgiLCIjZGY2NWIwIiwiI2RkMWM3NyIsIiM5ODAwNDMiKQpQbG90czwtbGlzdCgpCmNocjwtcGFzdGUwKCJjaHIiLCBjKDE6MjMsMjU6MjYpICkgI2V4Y2x1ZGUgY2hyMjQKZm9yIChpIGluIDE6bGVuZ3RoKGNocikpewogICAgQyA8LSBhcy5tYXRyaXgocmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvUENBYW5nc2QvUFdTb25seV9tYWYwNV8iLGNocltpXSwiLmNvdiIpKSkKICAgIGUgPC0gZWlnZW4oQykKICAgIHBjYSA8LWRhdGEuZnJhbWUoU2FtcGxlPXBvcHMkU2FtcGxlLCAKICAgICAgICAgICAgICAgICAgICAgcG9wPXBvcHMkcG9wLAogICAgICAgICAgICAgICAgICAgICB5ZWFyPXBvcHMkeWVhciwKICAgICAgICAgICAgICAgICAgICAgUEMxPWUkdmVjdG9yc1ssMV0sUEMyPWUkdmVjdG9yc1ssMl0sCiAgICAgICAgICAgICAgICAgICAgIFBDMz1lJHZlY3RvcnNbLDNdLFBDND1lJHZlY3RvcnNbLDRdLAogICAgICAgICAgICAgICAgICAgICBQQzU9ZSR2ZWN0b3JzWyw1XSxQQzY9ZSR2ZWN0b3JzWyw2XSwKICAgICAgICAgICAgICAgICAgICAgUEM3PWUkdmVjdG9yc1ssN10sUEM4PWUkdmVjdG9yc1ssOF0sCiAgICAgICAgICAgICAgICAgICAgIHN0cmluZ3NBc0ZhY3RvcnM9RkFMU0UpCiAgICAKICAgIHByb3BfZXhwbGFpbmVkIDwtIGMoKQogICAgZm9yIChzIGluIGUkdmFsdWVzWzE6MTBdKSB7CiAgICAgICAgI3ByaW50KHMgLyBzdW0oZSR2YWx1ZXMpKQogICAgICAgIHByb3BfZXhwbGFpbmVkIDwtIGMocHJvcF9leHBsYWluZWQscm91bmQoKChzIC8gc3VtKGUkdmFsdWVzKSkqMTAwKSwyKSkKICAgIH0KICAgICN3cml0ZS5jc3YocGNhLCBwYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTb25seV9wY2FfIixjaHJbaV0sIi5jc3YiKSwgcm93Lm5hbWVzID0gRikKICAgIFBsb3RzW1tpXV08LWdncGxvdCgpKwogICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IHBjYSwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGZpbGwgPSBmYWN0b3IoeWVhciksIGNvbG9yID0gZmFjdG9yKHllYXIpLCBzaGFwZSA9IGZhY3Rvcih5ZWFyKSksIHNpemUgPSAzKSsKICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjMsMjUsMywyMSksIGd1aWRlPSJub25lIikrCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMChwY29scywiOTkiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXBjb2xzWzE6NF0pKwogICAgICAgIHhsYWIocGFzdGUoIlBDIDE6ICIsIHByb3BfZXhwbGFpbmVkWzFdLCIlXG4iLHNlcCA9ICIiKSkrCiAgICAgICAgeWxhYihwYXN0ZSgiUEMgMjogIiwgcHJvcF9leHBsYWluZWRbMl0sIiVcbiIsc2VwID0gIiIpKSsKICAgICAgICB0aGVtZV9idygpKwogICAgICAgIGdndGl0bGUocGFzdGUwKGNocltpXSkpKwogICAgICAgIGd1aWRlcyhzaGFwZSA9IGd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPWMoMjMsMjUsMywyMSkpLCBmaWxsPWd1aWRlX2xlZ2VuZChvdmVycmlkZS5hZXMgPXBhc3RlMChwY29scywiOTkiKSkpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKfQoKCntwZGYoIi4uL091dHB1dC9QQ0EvUFdTb25seV9QQ0FfYnlDaHJvbW9zb21lLnBkZiIsd2lkdGggPSAzNSwgaGVpZ2h0ID0gMzApCmRvLmNhbGwoZ3JpZC5hcnJhbmdlLCBjKFBsb3RzLCBuY29sPTUpKQpkZXYub2ZmKCkKfQoKZyA8LSBhcnJhbmdlR3JvYihkby5jYWxsKGdyaWQuYXJyYW5nZSwgYyhQbG90cywgbmNvbD01KSkpCmdnc2F2ZShnLCBmaWxlPSIuLi9PdXRwdXQvUENBL1BXU29ubHlfUENBX2J5Q2hyb21vc29tZS5wbmciLHdpZHRoID0gMzUsIGhlaWdodCA9IDMwKQoKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfUENBX2J5Q2hyb21vc29tZS5wbmcpICAKVGhlIHNlcGFyYXRpb24gYW1vbmcgeWVhcnMgYXJlIG5vdCBzbyBjbGVhciBidXQgY2x1c3RlcmluZyBpbnRvIDMgZ3JvdXBzIGFyZSB2aXNpYmxlIGluIENocjQsOCwxNSwyMC4gCgo8YnI+CgoKIyBMb29rIGF0IGVhY2ggY2hyb21vc29tZSwgc3RhcnRpbmcgd2l0aCBDaHIxNSAgCgojIyBQV1MgQ2hyb21vc29tZSAxNSBncm91cGVkIGludG8gMyAoUEMxID4xMCUpICAKQ2hyMTUgc2hvd3MgdGhlIGxhcmdlc3QgcHJvcG9ydGlvbiBleHBsYWluZWQgYnkgUEMxIChzdHJvbmdlc3QgY2x1c3RlcmluZykKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0KI3Byb3BvcnRpb24gb2YgeWVhciBpbiBlYWNoIGdyb3VwCmNoMTU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL1BXU29ubHlfcGNhX2NocjE1LmNzdiIpCmdwMTwtY2gxNVtjaDE1JFBDMTwwLF0KZ3AyPC1jaDE1W2NoMTUkUEMxPj0wJmNoMTUkUEMxPDAuMDc1LF0KZ3AzPC1jaDE1W2NoMTUkUEMxPjAuMDc1LF0KCnRhYmxlKGdwMSR5ZWFyKQojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgMjUgICAzOSAgIDIzICAgMjIgCiAgCnRhYmxlKGdwMiR5ZWFyKQojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgMjIgICAyOCAgIDIxICAgMjMgCnRhYmxlKGdwMyR5ZWFyKQojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIzExICAgIDUgICAgMiAgIDExIAoKbm88LXRhYmxlKHBvcHMkeWVhcikKIzE5OTEgMTk5NiAyMDA3IDIwMTcgCiMgIDU4ICAgNzIgICA0NiAgIDU2IAoKZ3AxJGdyb3VwPC0iR3JvdXAxIgpncDIkZ3JvdXA8LSJHcm91cDIiCmdwMyRncm91cDwtIkdyb3VwMyIKYzE1PC1yYmluZChncDEsZ3AyLGdwMykKYzE1JHlyLnBvcDwtcGFzdGUwKGMxNSRwb3AsIHN1YnN0cihjMTUkeWVhciwzLDQpKQp3cml0ZS5jc3YoYzE1LCIuLi9PdXRwdXQvUENBL2NocjE1X1BDQWdyb3Vwcy5jc3YiKQoKZ2dwbG90KCkrCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYzE1LCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgZmlsbCA9IGZhY3Rvcih5ZWFyKSwgY29sb3IgPSBmYWN0b3IoeWVhciksIHNoYXBlID0gZmFjdG9yKHllYXIpKSwgc2l6ZSA9IDMpKwogICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMywyNSwzLDIxKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKHBjb2xzLCI5OSIpLCBndWlkZT0ibm9uZSIpKwogICAgICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9cGNvbHNbMTo0XSkrCiAgICAgICAgeGxhYigiUEMgMSIpKwogICAgICAgIHlsYWIoIlBDIDIiKSsKICAgICAgICB0aGVtZV9idygpKwogICAgICAgIGdndGl0bGUoIkNocjE1IikrCiAgICAgICAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9YygyMywyNSwzLDIxKSksIGZpbGw9Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9cGFzdGUwKHBjb2xzLCI5OSIpKSkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICBzdGF0X2VsbGlwc2UoZGF0YT1jMTUsIGFlcyh4PVBDMSwgeT1QQzIsIGdyb3VwPWdyb3VwKSwgbGV2ZWw9MC45OTksY29sb3I9ImdyYXk1MCIsIHNpemU9MC4yKSsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeD0tMC4wNiwgeT0wLjIyLCBsYWJlbD0iR3JvdXAgMSIpKwogICAgYW5ub3RhdGUoInRleHQiLCB4PTAuMDEsIHk9MC4xOCwgbGFiZWw9Ikdyb3VwIDIiKSsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeD0wLjEyLCB5PTAuMTgsIGxhYmVsPSJHcm91cCAzIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL0NocjE1X1BDQV93aXRoR3JvdXBzLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNC41LGRwaT0zMDAgKQpgYGAKIVtdKC4uL091dHB1dC9QQ0EvQ2hyMTVfUENBX3dpdGhHcm91cHMucG5nKXt3aWR0aD03MCV9ICAKCiMjIyBDcmVhdGUgYSBzdW1tYXJ5IG9mIGdyb3VwIHByb3BvcnRpb25zIGluIGVhY2ggeWVhciAgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CiNDcmVhdGUgYSBzdW1tYXJ5CmNoMTVfc3VtbWFyeTwtZGF0YS5mcmFtZSh5ZWFyPWMoMTk5MSwxOTk2LDIwMDcsMjAxNykpCmNoMTVfc3VtbWFyeSRHcm91cDE8LWFzLnZlY3Rvcih0YWJsZShncDEkeWVhcikpCmNoMTVfc3VtbWFyeSRHcm91cDI8LWFzLnZlY3Rvcih0YWJsZShncDIkeWVhcikpCmNoMTVfc3VtbWFyeSRHcm91cDM8LWFzLnZlY3Rvcih0YWJsZShncDMkeWVhcikpCgojcXVpY2sgY2hpLXNxdWFyZSB0ZXN0IApjaGlzcS50ZXN0KGNoMTVfc3VtbWFyeVssMjo0XSkKIwlQZWFyc29uJ3MgQ2hpLXNxdWFyZWQgdGVzdAojWC1zcXVhcmVkID0gMTAuNjY3LCBkZiA9IDYsIHAtdmFsdWUgPSAwLjA5OTIyCiMyMDA3IHZzLiAyMDE3CmNoaXNxLnRlc3QoY2gxNV9zdW1tYXJ5W2MoMyw0KSwyOjRdKQojWC1zcXVhcmVkID0gNS40MTU2LCBkZiA9IDIsIHAtdmFsdWUgPSAwLjA2NjY4CgpjMTVtPC1tZWx0KGNoMTVfc3VtbWFyeSwgaWQudmFycz0ieWVhciIpCmdncGxvdChjMTVtLCBhZXMoeD1mYWN0b3IoeWVhciksIHk9dmFsdWUsIGZpbGw9dmFyaWFibGUpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC41LCBjb2xvcj0iZ3JheTQwIixwb3NpdGlvbiA9ICJmaWxsIikrCiAgICB0aGVtZV9saW5lZHJhdygpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYigiUHJvcG9ydGlvbiBvZiBpbmRpdmlkdWFscyIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmYmI0YWUiLCIjYjNjZGUzIiwiI2NjZWJjNSIpKSt4bGFiKCJZZWFyIikrZ2d0aXRsZSgiUFdTIENocjE1IikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU19jaDE1X3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfY2gxNV9wcm9wX2luZGl2aV9pbjNncm91cHMucG5nKXt3aWR0aD02MCV9ICAKClRoZSBwcm9wb3J0aW9ucyBvZiB0aGUgMyBncm91cHMgY2hhbmdlIG92ZXIgdGltZSAobWFyZ2luYWxseSBzaWduaWZpY2FudGx5IGRpZmZlcmVudC4gCjxicj4KCiMjIyBIb3cgYW5kIHdoZXJlIGRvIGdyb3VwcyBkaWZmZXI/IFBsb3QgRnN0IGFuZCBEeHkgYWxvbmcgdGhlIGNocm9tb3NvbWUgCgpVc2UgIlBvcEdlbm9tZSIgcGFja2FnZSB0byBhc3Nlc3MgRnN0LCBEeHksIGFuZCBwaS4gCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ2FsY3VsYXRlIEZzdCBhbW9uZyB0aGUgMyBncm91cHMgdXNpbmcgUG9wR2Vub21lCiMgcmVhZCBjaHIxNSBmcm9tIHRoZSAnUFdTb25seScgZmlsZQpwd3MgPC0gcmVhZERhdGEoIi4uL0RhdGEvbmV3X3ZjZi9QV1MvUFdTb25seV9jaHIxNS8iLCBmb3JtYXQgPSAiVkNGIiwgaW5jbHVkZS51bmtub3duID0gVFJVRSwgRkFTVCA9IFRSVUUpCgojYXNzaWduIGdyb3Vwcwpwb3BzJGdyb3VwPC0iR3JvdXAxIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgZ3AyJFNhbXBsZV08LSJHcm91cDIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBncDMkU2FtcGxlXTwtIkdyb3VwMyIKcG9wdWxhdGlvbnMgPC0gc3BsaXQocG9wcyRTYW1wbGUsIHBvcHMkZ3JvdXApCgpwd3M8LXNldC5wb3B1bGF0aW9ucyhwd3MsIHBvcHVsYXRpb25zLCBkaXBsb2lkID0gVCkKCiMgc2V0IHRoZSBjaHJvbW9zb21lIHNpemUKY2hyMTU8LTI4NzEzNTIxCgojIHNldCB3aW5kb3cgc2l6ZSBhbmQgd2luZG93IGp1bXAKd2luZG93X3NpemUgPC0gNTAwMDAKd2luZG93X2p1bXAgPC0gMTAwMDAKIyBtYWtlIGEgc2xpZGluZyB3aW5kb3cgZGF0YXNldApwd3Nfc3cgPC0gc2xpZGluZy53aW5kb3cudHJhbnNmb3JtKHB3cywgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKIyBjcmF0ZSBzbGlkaW5nIHdpbmRvdyBpbmZvCndpbmRvd3M8LXB3c19zd0ByZWdpb24ubmFtZXMKd2luZG93czwtZ3N1YigiICIsIiIsIHdpbmRvd3MpCndpbmRvd3M8LWdzdWIoIjoiLCIiLHdpbmRvd3MpCndpbmRvd19zdGFydDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzFdKSkKd2luZG93X3N0b3A8LWFzLmludGVnZXIoc2FwcGx5KHdpbmRvd3MsIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAiLSIpKVsyXSkpCndpbmRvdzwtZGF0YS5mcmFtZShzdGFydCA9IHdpbmRvd19zdGFydCwgc3RvcCA9IHdpbmRvd19zdG9wLCAKICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IHdpbmRvd19zdGFydCArICh3aW5kb3dfc3RvcC13aW5kb3dfc3RhcnQpLzIpCgojY2FsY3VsYXRlIGRpdmVyc2l0eSBzdGF0cwpwd3Nfc3cgPC0gZGl2ZXJzaXR5LnN0YXRzKHB3c19zdywgcGkgPSBUUlVFKQpwd3Nfc3cgPC0gRl9TVC5zdGF0cyhwd3Nfc3csIG1vZGUgPSAibnVjbGVvdGlkZSIpCgojIGV4dHJhY3QgbnVjbGVvdGlkZSBkaXZlcnNpdHkgYW5kIGNvcnJlY3QgZm9yIHdpbmRvdyBzaXplCm5kIDwtIHB3c19zd0BudWMuZGl2ZXJzaXR5LndpdGhpbi81MDAwMAoKIyBtYWtlIGdyb3VwIG5hbWUgdmVjdG9yCmdyb3VwbmFtZXMgPC0gc29ydCh1bmlxdWUocG9wcyRncm91cCkpCiMgc2V0IHBvcHVsYXRpb24gbmFtZXMKY29sbmFtZXMobmQpIDwtIHBhc3RlMChncm91cG5hbWVzLCAiX3BpIikKCiMgZXh0cmFjdCBmc3QgdmFsdWVzCmZzdCA8LSB0KHB3c19zd0BudWMuRl9TVC5wYWlyd2lzZSkKCiMgZXh0cmFjdCBkeHkgLSBwYWlyd2lzZSBhYnNvbHV0ZSBudWNsZW90aWRlIGRpdmVyc2l0eQpkeHkgPC0gZ2V0LmRpdmVyc2l0eShwd3Nfc3csIGJldHdlZW4gPSBUKVtbMl1dLzUwMDAwCgojIGdldCBjb2x1bW4gbmFtZXMgCnggPC0gY29sbmFtZXMoZnN0KQp4IDwtIHN1YigicG9wMSIsIGdyb3VwbmFtZXNbMV0sIHgpCnggPC0gc3ViKCJwb3AyIiwgZ3JvdXBuYW1lc1syXSwgeCkKeCA8LSBzdWIoInBvcDMiLCBncm91cG5hbWVzWzNdLCB4KQp4IDwtIHN1YigiLyIsICJfIiwgeCkKCmNvbG5hbWVzKGZzdCk8LXBhc3RlMCgiZnN0XyIseCkKY29sbmFtZXMoZHh5KTwtcGFzdGUwKCJkeHlfIix4KQoKI2NvbWJpbmUgYWxsIGRhdGEKcHdzX2RhdGEgPC0gYXNfdGliYmxlKGRhdGEuZnJhbWUod2luZG93LCBuZCwgZnN0LCBkeHkpKQoKY29tYjwtY29tYm4oZ3JvdXBuYW1lcywgMikKY29tYjwtdChjb21iKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZHQ8LXB3c19kYXRhWywgYygibWlkIiwgcGFzdGUwKCJmc3RfIiwgcG9wMSwiXyIscG9wMikscGFzdGUwKCJkeHlfIixwb3AxLCJfIixwb3AyKSwgcGFzdGUwKHBvcDEsIl9waSIpLHBhc3RlMChwb3AyLCJfcGkiKSkgXQogICAgICAgIGNvbG5hbWVzKGR0KVsyOjNdPC1jKCJGc3QiLCJEeHkiKQogICAgCiAgICAgICAgZHRfZzwtZ2F0aGVyKGR0LCAtbWlkLCBrZXkgPSAic3RhdCIsIHZhbHVlID0gInZhbHVlIikKICAgICAgICBkdF9nJHN0YXQ8LWZhY3RvcihkdF9nJHN0YXQsIGxldmVscz1jKCJGc3QiLCJEeHkiLGNvbG5hbWVzKGR0KVs0XSwgY29sbmFtZXMoZHQpWzVdKSkKICAgICAgICBnZ3Bsb3QoZHRfZywgYWVzKG1pZC8xMF42LCB2YWx1ZSwgY29sb3VyID0gc3RhdCkpICsgZ2VvbV9saW5lKCkrCiAgICAgICAgICAgIGZhY2V0X2dyaWQoc3RhdH4uLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICAgICAgICAgIHhsYWIoIlBvc2l0aW9uIChNYikiKSt5bGFiKCcnKSsKICAgICAgICAgICAgdGhlbWVfbGlnaHQoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrZ2d0aXRsZShwYXN0ZTAoIkNocjE1ICIscG9wMSwiIHZzLiIsIHBvcDIpKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IHNlcSgxLCBjaHIxNSwxICkpCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X0RpdmVyc2l0eV9zdGF0c19jaHIxNV8iLHBvcDEsIiB2cy4iLCBwb3AyLCIucG5nIiksIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKICAgIH0KYGBgCjxicj4KCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfRGl2ZXJzaXR5X3N0YXRzX2NocjE1X0dyb3VwMSB2cy5Hcm91cDIucG5nKSAgCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfRGl2ZXJzaXR5X3N0YXRzX2NocjE1X0dyb3VwMSB2cy5Hcm91cDMucG5nKQohW10oLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X0RpdmVyc2l0eV9zdGF0c19jaHIxNV9Hcm91cDIgdnMuR3JvdXAzLnBuZykKICAKUG9zaXRpb24gMC0xNi41TWIgc2hvd3MgYSBzdHJvbmcgZGlmZmVyZW50aWF0aW9uIGFtb25nIGdyb3Vwcy4gCjxicj4KCiMjIyBDaGVjayBpZiBhbiBpbnZlcnNpb24gaXMgdmlzaWJsZSBpbiB0aGUgZ2Vub3R5cGUtcGxvdCAgCgohW10oLi4vT3V0cHV0L2Noci9EUDcwMDAvY2hyMTUvUFdTb25seV9QV1M5Nl9jaHIxNS5wbmcpe3dpZHRoPTMwJX0gCiFbXSguLi9PdXRwdXQvY2hyL0RQNzAwMC9jaHIxNS9QV1Nvbmx5X1BXUzE3X2NocjE1LnBuZyl7d2lkdGg9MzAlfSAKICAKVGhlIHByb3BvcnRpb24gb2YgR3JvdXAyIGlzIGhpZ2hlciBpbiBQV1M5NiBhbmQgUFdTMDcgLT4gTW9yZSBoZXRlcm96eWdvdXMgc25wcyBpbiBQV1M5NiAmUFdTMDc/CgojIyMgQ2FsY3VsYXRlIEhldGVyb3p5Z29zaXR5IGZyb20gQU5HU0QgLnNhZiBmaWxlcwogLUNhbiBjYWxjdWxhdGUgaGV0ZXJvenlnb3NpdHkgZm9yIGFuIGVudGlyZSBjaHJvbW9zb21lIG9yIGdlbm9tZSBvbmx5IChub3QgdXNlZnVsIGZvciBhc3Nlc3Npbmcgd2l0aGluIGEgY2hyb21vc21lKQoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojZXN0aW1hdGUgaGV0ZXJvenlnb3NpdHkgZnJvbSAuc2FmIGZyb20gQU5HU0QgLT4gY2FuJ3QgZGl2aWRlIGhldCBpbnRvIHJlZ2lvbnMgIApwb3BuYW1lczwtYygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciKQoKaGV0PC1kYXRhLmZyYW1lKHBvcD1wb3BuYW1lcykKZm9yIChpIGluIDE6NCl7CiAgICBhPC1zY2FuKHBhc3RlMCgiLi4vRGF0YS9uZXdfdmNmL2FuZ3NkL2Zyb21CYW0vdW5mb2xkZWQvIixwb3BuYW1lc1tpXSwiX3VuZm9sZGVkLnNmcyIpKQogICAgaGV0JEhlW2ldPC1hWzJdL3N1bShhKQp9CgpoZXQKIyAgIHBvcCAgICAgaGVfYmFtCiMxIFBXUzkxIDAuMDI2NTM0NjMKIzIgUFdTOTYgMC4wMjg2NTM4OAojMyBQV1MwNyAwLjAyNTY0NDA4CiM0IFBXUzE3IDAuMDIzMzYzMzYKCmthYmxlKGhldCwgImh0bWwiKSAlPiUKICBrYWJsZV9zdHlsaW5nKGZ1bGxfd2lkdGggPSBGKQpgYGAKCiMjIyBDb21wYXJlIGhldGVyb3p5Z29zaXR5IHBlciByZWdpb24gcGVyIGdyb3VwIHBlciB5ZWFyIHVzaW5nIGJjZnRvb2xzClRoZSBmb2xsb3dpbmcgY29kZSBpcyByZWZlcnJlZCBhcyAiQm94MSIKYGBge2Jhc2ggZXZhbD1GQUxTRSwgZWNobz1UUlVFfQojQ2FsY3VsYXRlIGhldGVyb3p5Z29zaXR5IHBlciB3aW5kb3cgdXNpbmcgYmNmdG9vbHMgKGhldF9zdGF0c19QV1M5MS5zaCkKI2UuZy4gCmJjZnRvb2xzIHN0YXRzIC1yIGNocjE1OjAtMTAwMDAwIC1zIC0gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXU29ubHk5MV9tYWYwNS52Y2YuZ3ogfCBncmVwICdeUFNDJyA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1M5MS9QV1M5MV9zdGF0c18xCmJjZnRvb2xzIHN0YXRzIC1yIGNocjE1OjEwMDAwMC0yMDAwMDAgLXMgLSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTb25seTkxX21hZjA1LnZjZi5neiB8IGdyZXAgJ15QU0MnID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXUzkxL1BXUzkxX3N0YXRzXzIKIyBmb3IgZm9yIGFsbCByZWdpb25zLi4uCiMgcnVuIHNsdXJtIHNjcmlwdHMgKGhldF9zdGF0c1hZWC5zaCkKCiNDb252ZXJ0IHRoZSBvdXRwdXQgZmlsZXMgdG8gdGFiLWRlbGltaW50ZWQsIGFuZCBjYXQgdGhlbShjYXRGaWxlc19QV1M5MS5zaCkKZm9yIGYgaW4gKjsgZG8gc2VkIC1pICJzLyQvXHQkZi8iICRmOyBkb25lIApjYXQgJChscyAtdCkgPiBQV1M5MV9zdGF0c0ZpbGUKYGBgCgoKIyMjIFJlc3VsdHMgb2Ygb2JzZXJ2ZWQgaGV0ZXJvenlnb3NpdHkgKEhvKSBwZXIgeWVhciBmb3IgZWFjaCBncm91cAoqIFN1bW1hcml6ZSBIbyBiYXNlZCBvbiB0d28gcmVnaW9ucyAocmVnaW9uMT1oaWdoLUZzdCAofjE2LjVNYikgdnMuIHJlZ2lvbjI9bG93LUZzdCgxNi41fmVuZCkpCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0KIyMgUmVhZCB0aGUgc3RhdHMgZmlsZXMgYW5kIGNyZWF0ZSBoZXQgc3VtbWFyeQojIENhbGN1bGF0ZSBIbyBhbmQgSGUgZnJvbSBiY2Z0b29scyBzdGF0cyBvdXRwdXQgZmlsZXMgKHN0YXRzIGZyb20gUFdTb25seSBmaWxlcykKc2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL25ld192Y2YvUFdTb25seS8iLCBwYXR0ZXJuPSJfY2hyMTVfc3RhdHNGaWxlIikKSGV0X3N1bTwtZGF0YS5mcmFtZSgpCiNjMTU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL2NocjE1X1BDQWdyb3Vwcy5jc3YiLCByb3cubmFtZXMgPSAxKQpmb3IgKGkgaW4gMTpsZW5ndGgoc2ZpbGVzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5LyIsIHNmaWxlc1tpXSksIHNlcD0iXHQiLCBoZWFkZXI9RikKICAgIHBuYW1lPC1nc3ViKCJfY2hyMTVfc3RhdHNGaWxlIiwnJyxzZmlsZXNbaV0pCiAgICBwbmFtZTwtZ3N1YigiUFdTb25seV8iLCcnLCBwbmFtZSkKICAgIGRmPC1kZlssYygzOjEwLCAxNCldCiAgICBjb2xuYW1lcyhkZik8LWMoIlNhbXBsZSIsIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiLCAiblRyYW5zaXRpb25zIiwgIm5UcmFuc3ZlcnNpb25zIiwibkluZGVscyIsImF2ZXJhZ2UgZGVwdGgiLCJuTWlzc2luZyIsIndpbmRvd19ubyIpCiAgICBkZiRwPC0oMipkZiRuUmVmSG9tK2RmJG5IZXRzKS8ocm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkqMikKICAgIGRmJHE8LSgyKmRmJG5Ob25SZWZIb20rZGYkbkhldHMpLyhyb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKSoyKQogICAgCiAgICBkZiRIZTwtMipkZiRwKmRmJHEKICAgIGRmJEhvPC1kZiRuSGV0cy9yb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKQogICAgCiAgICBkZiRHcm91cDwtIkdyb3VwMSIKICAgIGRmJEdyb3VwW2RmJFNhbXBsZSAlaW4lIGMxNSRTYW1wbGVbYzE1JGdyb3VwPT0iR3JvdXAyIl1dPC0iR3JvdXAyIgogICAgZGYkR3JvdXBbZGYkU2FtcGxlICVpbiUgYzE1JFNhbXBsZVtjMTUkZ3JvdXA9PSJHcm91cDMiXV08LSJHcm91cDMiCiAgICAKICAgIEhvPC1hZ2dyZWdhdGUoZGZbLCJIbyJdLCBieT1saXN0KGRmJHdpbmRvd19ubywgZGYkR3JvdXApLCBtZWFuICkKICAgIEhlPC1hZ2dyZWdhdGUoZGZbLCJIZSJdLCBieT1saXN0KGRmJHdpbmRvd19ubyxkZiRHcm91cCksIG1lYW4gKQogICAgaGV0PC1jYmluZChIbywgSGUkeCkKICAgIGNvbG5hbWVzKGhldCk8LWMoIndpbmRvd19pZCIsIkdyb3VwIiwiSG8iLCJIZSIpCiAgICB3cml0ZS5jc3YoaGV0LHBhc3RlMCgiLi4vT3V0cHV0L1N0YXRzX3dpbmRvdy9QV1Nvbmx5X2NocjE1X0hldGVyb3pfIixwbmFtZSwiX21hZjA1LmNzdiIpKQogICAgCiAgICBoZXQkd2luZG93PC1hcy5pbnRlZ2VyKGdzdWIocGFzdGUwKHBuYW1lLCJfc3RhdHNfIiksJycsaGV0JHdpbmRvd19pZCkpCiAgICBoZXQkbG9jPC0icmVnaW9uMSIKICAgIGhldCRsb2NbaGV0JHdpbmRvdz4xNjVdPC0icmVnaW9uMiIKICAgIAogICAgZ3JvdXBIbzwtYWdncmVnYXRlKGhldFssIkhvIl0sIGJ5PWxpc3QoaGV0JEdyb3VwLCBoZXQkbG9jKSwgbWVhbiAsIG5hLnJtPVQpCiAgICBjb2xuYW1lcyhncm91cEhvKTwtYygiR3JvdXAiLCJSZWdpb24iLCJIbyIpCiAgICBncm91cEhvJHllYXI8LXBuYW1lCiAgICBIZXRfc3VtPC1yYmluZChIZXRfc3VtLGdyb3VwSG8pCn0KCndyaXRlLmNzdihIZXRfc3VtLCAiLi4vT3V0cHV0L1N0YXRzX3dpbmRvdy9QV1Nvbmx5X2NocjE1X0hldGVyb19ncm91cF9zdW1tYXJ5LmNzdiIpCmBgYAoKCmBgYHtyIGVjaG89RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsZXZhbD1GQUxTRX0KI0NyZWF0ZSBhIGZpZ3VyZQpwb3BzPC1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIpCgpIZXQ8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgocG9wcykpewogICAgZGY8LXJlYWQuY3N2KHBhc3RlMCgiLi4vT3V0cHV0L1N0YXRzX3dpbmRvdy9QV1Nvbmx5X2NocjE1X0hldGVyb3pfIixwb3BzW2ldLCJfbWFmMDUuY3N2IiksIHJvdy5uYW1lcyA9IDEpCiAgICBkZiR3aW5kb3c8LWFzLmludGVnZXIoZ3N1YihwYXN0ZTAocG9wc1tpXSwiX3N0YXRzXyIpLCcnLGRmJHdpbmRvd19pZCkpCiAgICBkZiRsb2M8LSJyZWdpb24xIgogICAgZGYkbG9jW2RmJHdpbmRvdz4xNjVdPC0icmVnaW9uMiIKICAgIGRmJHBvcDwtcG9wc1tpXQogICAgSGV0PC1yYmluZChIZXQsZGYpICAgIAp9CgpnY29sczwtYygiI0ZCNjg3QiIsIiM0OEFCRTMiLCIjNzVCQTc2IikKSGV0JHBvcDwtZmFjdG9yKEhldCRwb3AsIGxldmVscz1wb3BzKQojSGV0X3N1bTwtcmVhZC5jc3YoIi4uL091dHB1dC9TdGF0c193aW5kb3cvUFdTb25seV9jaHIxNV9IZXRlcm9fZ3JvdXBfc3VtbWFyeS5jc3YiLCByb3cubmFtZXMgPSAxKQoKY29sbmFtZXMoSGV0X3N1bSlbNF08LSJwb3AiCkhldF9zdW0kcG9wPC1mYWN0b3IoSGV0X3N1bSRwb3AsIGxldmVscz1wb3BzKQoKZ2dwbG90KCkrCiAgICBnZW9tX2JveHBsb3QoZGF0YT1IZXQsYWVzKHg9bG9jLCB5PUhvLCBjb2xvcj1Hcm91cCwgZmlsbD1Hcm91cCksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0wLjgpLG91dGxpZXIuYWxwaGEgPSAwLjYsIG91dGxpZXIuc2l6ZSA9IDEsd2lkdGg9MC43KSsKICAgIGdlb21fcG9pbnQoZGF0YT1IZXRfc3VtLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICBmYWNldF93cmFwKH5wb3ApKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41KSwgY29sb3I9ImdyYXk3MCIsc2l6ZT0wLjMpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1nY29scykrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKGdjb2xzLCAiNjYiKSkreGxhYignJykKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU19DaHIxNV9Iby5pbi50d29yZWdpb25zLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNywgZHBpPTMwMCkKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19DaHIxNV9Iby5pbi50d29yZWdpb25zLnBuZykgIApPYnNlcnZlZCBoZXRlcm96eWdvc2l0eSAoSG8pIGlzIGhpZ2hlciBpbiBHcm91cDIgdGhhbiBHcm91cDEgaW4gUmVnaW9uIDEgKHRoZSBoeXBvdGhldGljYWwgaW52ZXJzaW9uIHJlZ2lvbikuCkhldGVyb3p5Z29zaXR5IGFwcGVhcmVkIHRvIGJlIHN1cHByZXNzZWQgaW4gR3JvdXAxLiAKCjxicj4KCiMjIENocjE1IGdyb3VwIHByb3BvcnRpb25zIGluIG90aGVyIHBvcHVsYXRpb25zIAojIyMgKjMgZ3JvdXBzIG9mIFBXUyBhcmUgdGhlIHNhbWUgZm9yIGFsbCBwb3B1bGF0aW9ucyBjb25zaWRlcmVkCgohW2FsbCBwb3BzXSguLi9PdXRwdXQvY2hyL2NoMTVfYWxsLnBuZyl7d2lkdGg9MzAlfSAgIVtubyBUQl0oLi4vT3V0cHV0L2Noci9jaDE1X25vVEIucG5nKXt3aWR0aD0zMCV9ICAKCiMjIyBTdW1tYXJ5IG9mIGdyb3VwIHByb3BvcnRpb25zIGZvciBlYWNoIHBvcCAgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CiNmcm9tIENocl9BbmFseXNpcy5SCmdwMTU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL2NocjE1X1BDQWdyb3Vwcy5jc3YiLCByb3cubmFtZXMgPSAxKQojZG91YmxlIGNoZWNrIHRoZSBzYW1lIGluZGl2aWR1bGFzIGFyZSBpbiB0aGUgc2FtZSBncm91cHMgZm9yIFBXUyBwb3BzCgpzZXRlcXVhbChncDE1JFNhbXBsZVtncDE1JEdyb3VwPT0iR3JvdXAxIiZncDE1JHBvcD09IlBXUyJdLCBjMTUkU2FtcGxlW2MxNSRHcm91cD09Ikdyb3VwMSJdKQpzZXRlcXVhbChncDE1JFNhbXBsZVtncDE1JEdyb3VwPT0iR3JvdXAzIiZncDE1JHBvcD09IlBXUyJdLCBjMTUkU2FtcGxlW2MxNSRHcm91cD09Ikdyb3VwMyJdKQoKcG9wLnN1bTwtZ3AxNSAlPiUgY291bnQoR3JvdXAsIHlyLnBvcCkKCnBvcC5zdW0keXIucG9wPC1mYWN0b3IocG9wLnN1bSR5ci5wb3AsIGxldmVscz1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIsIlNTOTYiLCJTUzA2IiwiU1MxNyIsIkJDMTciLCJXQTE3IiwiQ0ExNyIpKQpnZ3Bsb3QoZGF0YT1wb3Auc3VtLCBhZXMoeD15ci5wb3AsIHk9biwgZmlsbD1mYWN0b3IoR3JvdXApKSkrCiAgICBnZW9tX2Jhcihwb3NpdGlvbj0iZmlsbCIsIHN0YXQ9ImlkZW50aXR5IiwgY29sb3I9ImdyYXkzMCIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmYmI0YWUiLCIjYjNjZGUzIiwiI2NjZWJjNSIpLCBsYWJlbHM9YygiR3JvdXAxIiwiR3JvdXAyIiwiR3JvdXAzIikpKwogICAgdGhlbWVfbGlnaHQoKStnZ3RpdGxlKCJDaHIxNSIpKwogICAgeGxhYigiIikreWxhYigiUHJvcG9ydGlvbiIpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL0NocjE1XzNncm91cHNfYmFycGxvdF9hbGxQb3BzLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNS41LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9QQ0EvQ2hyMTVfM2dyb3Vwc19iYXJwbG90X2FsbFBvcHMucG5nKXt3aWR0aD03NSV9ClRoZSBtYWpvcml0eSBvZiBDQSBpbmRpdmlkdWFscyBhcmUgaW4gR3JvdXAgMiAmIDMsIHdoaWxlIG90aGVycyBhcmUgR3JvdXAgMSAmIDIuICAKUFdTIHBvcHVsYXRpb25zIGFyZSB1bmlxdWVseSBkaWZmZXJuZXQgZnJvbSBTUyBwb3BzLgo8YnI+CgojIyMgQ29tcGFyZSBoZXRlcm96eWdvc2l0eSBhbW9uZyBncm91cHMgZm9yIGFsbCBwb3BzIAoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgaW5jbHVkZT1GQUxTRX0KIyAxLiBkaXZpZGUgdGhlIFZDRiBmaWxlIGludG8gZWFjaCBncm91cCAoc3Vic2V0VkNGX2J5Q2hyb20xNS5zaCkKIyAyLiBJbmRleCB0aGUgdmNmIGZpbGVzCiMgMy4gY2FsY3VsYXRlIGhldGVyb3p5Z29zaXR5IHN0YXRzIHBlciBncm91cCAoaGV0X3N0YXRzZ3JvdXAxLnNoIH4gaGV0X3N0YXRzZ3JvdXAzLnNoKQojIDQuIGNoYW5nZSB0aGUgb3V0cHV0IGludG8gdGFiLWRlbGltaXRlZCBhbmQgY29uY2F0aW5hdGUKZm9yIGYgaW4gKjsgZG8gc2VkIC1pICJzLyQvXHQkZi8iICRmOyBkb25lIApjYXQgJChscyAtdCkgPiBQV1M5MV9zdGF0c0ZpbGUKYGBgCgojIyMjIGhldGVyb3p5Z29zaXR5IGlzIGhpZ2hlciBpbiBHcm91cDIgKFRoZSBzYW1lIHBhdHRlcm4gYXMgaW4gUFdTKQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBDYWxjdWxhdGUgSG8gYW5kIEhlIGZyb20gYmNmdG9vbHMgc3RhdHMgb3V0cHV0IGZpbGVzCnNmaWxlczwtbGlzdC5maWxlcygiLi4vRGF0YS9uZXdfdmNmL2NoMTUvIiwgcGF0dGVybj0iX21hZjA1X3N0YXRzRmlsZSIpCmdyb3VwczwtcGFzdGUwKCJncm91cCIsMTozKQpIZXQ8LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgoc2ZpbGVzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9jaDE1LyIsIHNmaWxlc1tpXSksIHNlcD0iXHQiLCBoZWFkZXI9RikKICAgIGRmPC1kZlssYygzOjEwLCAxNDoxNSldCiAgICBjb2xuYW1lcyhkZik8LWMoIlNhbXBsZSIsIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiLCAiblRyYW5zaXRpb25zIiwgIm5UcmFuc3ZlcnNpb25zIiwibkluZGVscyIsImF2ZXJhZ2UgZGVwdGgiLCJuTWlzc2luZyIsIndpbmRvd19ubyIpCiAgICBkZiRwPC0oMipkZiRuUmVmSG9tK2RmJG5IZXRzKS8ocm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkqMikKICAgIGRmJHE8LSgyKmRmJG5Ob25SZWZIb20rZGYkbkhldHMpLyhyb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKSoyKQogICAgZGYkSGU8LTIqZGYkcCpkZiRxCiAgICBkZiRIbzwtZGYkbkhldHMvcm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkKICAgIAogICAgSG88LWFnZ3JlZ2F0ZShkZlssIkhvIl0sIGJ5PWxpc3QoZGYkd2luZG93X25vKSwgbWVhbiApCiAgICBIZTwtYWdncmVnYXRlKGRmWywiSGUiXSwgYnk9bGlzdChkZiR3aW5kb3dfbm8pLCBtZWFuICkKICAgIGhldDwtY2JpbmQoSG8sIEhlJHgpCiAgICBjb2xuYW1lcyhoZXQpPC1jKCJ3aW5kb3dfaWQiLCJIbyIsIkhlIikKICAgIGhldCRHcm91cDwtcGFzdGUwKCJHcm91cCIsaSkKICAgIGhldCR3aW5kb3c8LWFzLmludGVnZXIoZ3N1YihwYXN0ZTAoInBoX2NoMTVfIixncm91cHNbaV0sIl9zdGF0c18iKSwnJyxoZXQkd2luZG93X2lkKSkKICAgIEhldDwtcmJpbmQoSGV0LGhldCkKfQogCkhldCRsb2M8LSJyZWdpb24xIgpIZXQkbG9jW0hldCR3aW5kb3c+MTY1XTwtInJlZ2lvbjIiCndyaXRlLmNzdihIZXQsICIuLi9PdXRwdXQvUENBL0NocjE1X0hvX2J5R3JvdXBzLmNzdiIpICAgIAoKZ3JvdXBIbzwtYWdncmVnYXRlKEhldFssIkhvIl0sIGJ5PWxpc3QoSGV0JEdyb3VwLCBIZXQkbG9jKSwgbWVhbiAsIG5hLnJtPVQpCmNvbG5hbWVzKGdyb3VwSG8pPC1jKCJHcm91cCIsIlJlZ2lvbiIsIkhvIikKd3JpdGUuY3N2KGdyb3VwSG8sICIuLi9PdXRwdXQvU3RhdHNfd2luZG93L0NocjE1X0hldGVyb19ncm91cDEtM19zdW1tYXJ5LmNzdiIpCgojUGxvdCB0aGUgcmVzdWx0cwpnY29sczwtYygiI0ZCNjg3QiIsIiM0OEFCRTMiLCIjNzVCQTc2IikKZ2dwbG90KCkrCiAgICBnZW9tX2JveHBsb3QoZGF0YT1IZXQsYWVzKHg9bG9jLCB5PUhvLCBjb2xvcj1Hcm91cCwgZmlsbD1Hcm91cCksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0wLjgpLG91dGxpZXIuYWxwaGEgPSAwLjYsIG91dGxpZXIuc2l6ZSA9IDEsd2lkdGg9MC43KSsKICAgIGdlb21fcG9pbnQoZGF0YT1ncm91cEhvLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygxLjUpLCBjb2xvcj0iZ3JheTcwIixzaXplPTAuMykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdjb2xzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoZ2NvbHMsICI2NiIpKSt4bGFiKCcnKQpnZ3NhdmUoIi4uL091dHB1dC9QQ0EvQ2hyMTVfSG8uYWxscG9wc19pbi50d29yZWdpb25zLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BDQS9DaHIxNV9Iby5hbGxwb3BzX2luLnR3b3JlZ2lvbnMucG5nKXt3aWR0aD03MCV9ICAKCgojIyMjICBIZXRlcm96eWdvc2l0eSB1c2luZyBtYWYwLjAxIHZjZiBmaWxlcyBmb3IgY29tcGFyaXNvbiAKSG8gcGF0dGVybnMgYXJlIGhpZ2hseSBzaW1pbGFyIHRvIHRoYXQgb2YgbWFmMC4wNS4KYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KIyBIbyB1c2luZyBtYWYwMSBmaWxlcyBmb3IgY29tcGFyaXNvbgpzZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmV3X3ZjZi9jaDE1LyIsIHBhdHRlcm49Il9tYWYwMV9zdGF0c0ZpbGUiKQpjMTU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL2NocjE1X1BDQWdyb3Vwcy5jc3YiLCByb3cubmFtZXMgPSAxKQpncm91cHM8LXBhc3RlMCgiZ3JvdXAiLDE6MykKSGV0PC1kYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHNmaWxlcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvY2gxNS8iLCBzZmlsZXNbaV0pLCBzZXA9Ilx0IiwgaGVhZGVyPUYpCiAgICBkZjwtZGZbLGMoMzoxMCwgMTQ6MTUpXQogICAgY29sbmFtZXMoZGYpPC1jKCJTYW1wbGUiLCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIiwgIm5UcmFuc2l0aW9ucyIsICJuVHJhbnN2ZXJzaW9ucyIsIm5JbmRlbHMiLCJhdmVyYWdlIGRlcHRoIiwibk1pc3NpbmciLCJ3aW5kb3dfbm8iKQogICAgZGYkcDwtKDIqZGYkblJlZkhvbStkZiRuSGV0cykvKHJvd1N1bXMoZGZbLGMoIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiKV0pKjIpCiAgICBkZiRxPC0oMipkZiRuTm9uUmVmSG9tK2RmJG5IZXRzKS8ocm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkqMikKICAgIGRmJEhlPC0yKmRmJHAqZGYkcQogICAgZGYkSG88LWRmJG5IZXRzL3Jvd1N1bXMoZGZbLGMoIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiKV0pCiAgICAKICAgIEhvPC1hZ2dyZWdhdGUoZGZbLCJIbyJdLCBieT1saXN0KGRmJHdpbmRvd19ubyksIG1lYW4gKQogICAgSGU8LWFnZ3JlZ2F0ZShkZlssIkhlIl0sIGJ5PWxpc3QoZGYkd2luZG93X25vKSwgbWVhbiApCiAgICBoZXQ8LWNiaW5kKEhvLCBIZSR4KQogICAgY29sbmFtZXMoaGV0KTwtYygid2luZG93X2lkIiwiSG8iLCJIZSIpCiAgICBoZXQkR3JvdXA8LXBhc3RlMCgiR3JvdXAiLGkpCiAgICBoZXQkd2luZG93PC1hcy5pbnRlZ2VyKGdzdWIocGFzdGUwKCJwaF9jaDE1XyIsZ3JvdXBzW2ldLCJfbWFmMDFfc3RhdHNfIiksJycsaGV0JHdpbmRvd19pZCkpCiAgICBIZXQ8LXJiaW5kKEhldCxoZXQpCn0KIApIZXQkbG9jPC0icmVnaW9uMSIKSGV0JGxvY1tIZXQkd2luZG93PjE2NV08LSJyZWdpb24yIgp3cml0ZS5jc3YoSGV0LCAiLi4vT3V0cHV0L1BDQS9DaHIxNV9Ib19ieUdyb3Vwc19tYWYwMS5jc3YiKSAgICAKCmdyb3VwSG88LWFnZ3JlZ2F0ZShIZXRbLCJIbyJdLCBieT1saXN0KEhldCRHcm91cCwgSGV0JGxvYyksIG1lYW4gLCBuYS5ybT1UKQpjb2xuYW1lcyhncm91cEhvKTwtYygiR3JvdXAiLCJSZWdpb24iLCJIbyIpCndyaXRlLmNzdihncm91cEhvLCAiLi4vT3V0cHV0L1N0YXRzX3dpbmRvdy9DaHIxNV9IZXRlcm9fZ3JvdXAxLTNfc3VtbWFyeV9tYWYwMS5jc3YiKQoKI1Bsb3QgdGhlIHJlc3VsdHMKZ2NvbHM8LWMoIiNGQjY4N0IiLCIjNDhBQkUzIiwiIzc1QkE3NiIpCmdncGxvdCgpKwogICAgZ2VvbV9ib3hwbG90KGRhdGE9SGV0LGFlcyh4PWxvYywgeT1IbywgY29sb3I9R3JvdXAsIGZpbGw9R3JvdXApLCBwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSxvdXRsaWVyLmFscGhhID0gMC42LCBvdXRsaWVyLnNpemUgPSAxLHdpZHRoPTAuNykrCiAgICBnZW9tX3BvaW50KGRhdGE9Z3JvdXBIbywgYWVzKHg9UmVnaW9uLCB5PUhvLCBjb2xvcj1Hcm91cCkscG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPTAuOCkpKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41KSwgY29sb3I9ImdyYXk3MCIsc2l6ZT0wLjMpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1nY29scykrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKGdjb2xzLCAiNjYiKSkreGxhYignJykKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL0NocjE1X0hvLmFsbHBvcHNfaW4udHdvcmVnaW9uc19tYWYwMS5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDMuNSwgZHBpPTMwMCkKCmBgYAohW10oLi4vT3V0cHV0L1BDQS9DaHIxNV9Iby5hbGxwb3BzX2luLnR3b3JlZ2lvbnMucG5nKXt3aWR0aD03MCV9ICAgCiogdmVyeSBzaW1pbGFyIHRvIG1hZjAuMDUsIG1lYW5pbmcgbm8gbmVlZCB0byB1c2UgbWFmMDEgZmlsZXMKCjxicj4KPGJyPgoKIyBDaHI4ICAgCgojIyBQV1MgQ2hyb21vc29tZSA4IGdyb3VwZWQgaW50byAzIChQQzEgPSA1LjglKSAgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojcHJvcG9ydGlvbiBvZiB5ZWFyIGluIGVhY2ggZ3JvdXAKY2g4PC1yZWFkLmNzdigiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X3BjYV9jaHI4LmNzdiIpCmdwMTwtY2g4W2NoOCRQQzE8MCxdCmdwMjwtY2g4W2NoOCRQQzE+MCZjaDgkUEMxPDAuMSxdCmdwMzwtY2g4W2NoOCRQQzE+MC4xLF0KCnRhYmxlKGdwMSR5ZWFyKSAjMTQwCiMxOTkxIDE5OTYgMjAwNyAyMDE3IAojICAzNyAgIDUxICAgMjcgICAyNSAKdGFibGUoZ3AyJHllYXIpICM4MwojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgMTkgICAxOSAgIDE3ICAgMjggCnRhYmxlKGdwMyR5ZWFyKSAjOQojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgIDIgICAgMiAgICAyICAgIDMgCgpubzwtdGFibGUocG9wcyR5ZWFyKQojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgNTggICA3MiAgIDQ2ICAgNTYgCgpncDEkZ3JvdXA8LSJHcm91cDEiCmdwMiRncm91cDwtIkdyb3VwMiIKZ3AzJGdyb3VwPC0iR3JvdXAzIgpjODwtcmJpbmQoZ3AxLGdwMixncDMpCndyaXRlLmNzdihjOCwgIi4uL091dHB1dC9QQ0EvUFdTb25seV93aXRoLmdyb3Vwc19wY2FfY2hyOC5jc3YiKQoKZ2dwbG90KCkrCiAgICAgICAgZ2VvbV9wb2ludChkYXRhID0gYzgsIGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBmaWxsID0gZmFjdG9yKHllYXIpLCBjb2xvciA9IGZhY3Rvcih5ZWFyKSwgc2hhcGUgPSBmYWN0b3IoeWVhcikpLCBzaXplID0gMykrCiAgICAgICAgc2NhbGVfc2hhcGVfbWFudWFsKHZhbHVlcz1jKDIzLDI1LDMsMjEpLCBndWlkZT0ibm9uZSIpKwogICAgICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAocGNvbHMsIjk5IiksIGd1aWRlPSJub25lIikrCiAgICAgICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1wY29sc1sxOjRdKSsKICAgICAgICB4bGFiKHBhc3RlKCJQQyAxIikpKwogICAgICAgIHlsYWIocGFzdGUoIlBDIDIiKSkrCiAgICAgICAgdGhlbWVfYncoKSsKICAgICAgICBnZ3RpdGxlKCJDaHI4IikrCiAgICAgICAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9YygyMywyNSwzLDIxKSksIGZpbGw9Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9cGFzdGUwKHBjb2xzLCI5OSIpKSkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICBzdGF0X2VsbGlwc2UoZGF0YT1jOCwgYWVzKHg9UEMxLCB5PVBDMiwgZ3JvdXA9Z3JvdXApLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0wLjIsbGV2ZWw9MC45OTUpKwogICAgYW5ub3RhdGUoInRleHQiLCB4PS0wLjAzLCB5PTAuMjUsIGxhYmVsPSJHcm91cCAxIikrCiAgICBhbm5vdGF0ZSgidGV4dCIsIHg9MC4wMzUsIHk9MC4yLCBsYWJlbD0iR3JvdXAgMiIpKwogICAgYW5ub3RhdGUoInRleHQiLCB4PTAuMTgsIHk9MC4yLCBsYWJlbD0iR3JvdXAgMyIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9DaDhfUENBX3dpdGhHcm91cHNfbm9UQi5wbmciLCB3aWR0aCA9IDYuNSwgaGVpZ2h0ID0gNC41LCBkcGk9MzAwKQojVEIgaXMgaW4gMSBncm91cApgYGAKIVtdKC4uL091dHB1dC9QQ0EvQ2g4X1BDQV93aXRoR3JvdXBzX25vVEIucG5nKXt3aWR0aD03NSV9CgojIyMgQ2FsY3VsYXRlIHRoZSBncm91cCBwcm9wb3J0aW9ucyBmb3IgZWFjaCB5ZWFyCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGEgc3VtbWFyeQpjaDhfc3VtbWFyeTwtZGF0YS5mcmFtZSh5ZWFyPWMoMTk5MSwxOTk2LDIwMDcsMjAxNykpCmNoOF9zdW1tYXJ5JEdyb3VwMTwtYXMudmVjdG9yKHRhYmxlKGdwMSR5ZWFyKSkKY2g4X3N1bW1hcnkkR3JvdXAyPC1hcy52ZWN0b3IodGFibGUoZ3AyJHllYXIpKQpjaDhfc3VtbWFyeSRHcm91cDM8LWFzLnZlY3Rvcih0YWJsZShncDMkeWVhcikpCgojcXVpY2sgY2hpLXNxdWFyZSB0ZXN0IApjaGlzcS50ZXN0KGNoOF9zdW1tYXJ5WywyOjRdKQojCVBlYXJzb24ncyBDaGktc3F1YXJlZCB0ZXN0CiNYLXNxdWFyZWQgPSA5LjQzNTcsIGRmID0gNiwgcC12YWx1ZSA9IDAuMTUwNQoKY2hpc3EudGVzdChjaDhfc3VtbWFyeVtjKDIsNCksMjo0XSkgI1BXUzk2IHZzLiBQV1MxNwojWC1zcXVhcmVkID0gOC45NTgxLCBkZiA9IDIsIHAtdmFsdWUgPSAwLjAxMTM0CiMKYzhtPC1tZWx0KGNoOF9zdW1tYXJ5LCBpZC52YXJzPSJ5ZWFyIikKZ2dwbG90KGM4bSwgYWVzKHg9ZmFjdG9yKHllYXIpLCB5PXZhbHVlLCBmaWxsPXZhcmlhYmxlKSkrCiAgICBnZW9tX2JhcihzdGF0PSJpZGVudGl0eSIsIHdpZHRoPTAuNSwgY29sb3I9ImdyYXk0MCIscG9zaXRpb24gPSAiZmlsbCIpKwogICAgdGhlbWVfbGluZWRyYXcoKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpK3lsYWIoIlByb3BvcnRpb24gb2YgaW5kaXZpZHVhbHMiKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1jKCIjZmJiNGFlIiwiI2IzY2RlMyIsIiNjY2ViYzUiKSkreGxhYigiWWVhciIpK2dndGl0bGUoIlBXUyBDaHI4IikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU19jaDhfcHJvcF9pbmRpdmlfaW4zZ3JvdXBzLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDhfcHJvcF9pbmRpdmlfaW4zZ3JvdXBzLnBuZyl7d2lkdGg9NzAlfQpDaHI4IGdyb3VwIHByb3BvcnRpb25zIGFsc28gc2hpZnQgd2l0aCB5ZWFycy4gIAoKIyMjIFBsb3QgRnN0IGFuZCBEeHkgYWxvbmcgdGhlIGNocm9tb3NvbWUgCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0V9CiMgcmVhZCBjaHI4IGZyb20gdGhlICdQV1Nvbmx5JyBmaWxlCnB3cyA8LSByZWFkRGF0YSgiLi4vRGF0YS9uZXdfdmNmL1BXU29ubHkvUFdTb25seV9jaHI4LyIsIGZvcm1hdCA9ICJWQ0YiLCBpbmNsdWRlLnVua25vd24gPSBUUlVFLCBGQVNUID0gVFJVRSkKCnBvcHM8LXBvcF9pbmZvW3BvcF9pbmZvJHBvcD09IlBXUyIsXQojYXNzaWduIGdyb3Vwcwpwb3BzJGdyb3VwPC0iR3JvdXAxIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgZ3AyJFNhbXBsZV08LSJHcm91cDIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBncDMkU2FtcGxlXTwtIkdyb3VwMyIKCnBvcHVsYXRpb25zIDwtIHNwbGl0KHBvcHMkU2FtcGxlLCBwb3BzJGdyb3VwKQoKcHdzPC1zZXQucG9wdWxhdGlvbnMocHdzLCBwb3B1bGF0aW9ucywgZGlwbG9pZCA9IFQpCgojIHNldCB0aGUgY2hyb21vc29tZSBzaXplCmNocnNpemU8LXJlYWQudGFibGUoIi4uL0RhdGEvbmV3X3ZjZi9jaHJfc2l6ZXMuYmVkIikKY2hyODwtY2hyc2l6ZSRWM1tjaHJzaXplJFYxPT0iY2hyOCJdCgojIHNldCB3aW5kb3cgc2l6ZSBhbmQgd2luZG93IGp1bXAKd2luZG93X3NpemUgPC0gNTAwMDAKd2luZG93X2p1bXAgPC0gMTAwMDAKIyBtYWtlIGEgc2xpZGluZyB3aW5kb3cgZGF0YXNldApwd3Nfc3cgPC0gc2xpZGluZy53aW5kb3cudHJhbnNmb3JtKHB3cywgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKIyBjcmF0ZSBzbGlkaW5nIHdpbmRvdyBpbmZvCndpbmRvd3M8LXB3c19zd0ByZWdpb24ubmFtZXMKd2luZG93czwtZ3N1YigiICIsIiIsIHdpbmRvd3MpCndpbmRvd3M8LWdzdWIoIjoiLCIiLHdpbmRvd3MpCndpbmRvd19zdGFydDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzFdKSkKd2luZG93X3N0b3A8LWFzLmludGVnZXIoc2FwcGx5KHdpbmRvd3MsIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAiLSIpKVsyXSkpCndpbmRvdzwtZGF0YS5mcmFtZShzdGFydCA9IHdpbmRvd19zdGFydCwgc3RvcCA9IHdpbmRvd19zdG9wLCAKICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IHdpbmRvd19zdGFydCArICh3aW5kb3dfc3RvcC13aW5kb3dfc3RhcnQpLzIpCgojY2FsY3VsYXRlIGRpdmVyc2l0eSBzdGF0cwpwd3Nfc3cgPC0gZGl2ZXJzaXR5LnN0YXRzKHB3c19zdywgcGkgPSBUUlVFKQpwd3Nfc3cgPC0gRl9TVC5zdGF0cyhwd3Nfc3csIG1vZGUgPSAibnVjbGVvdGlkZSIpCgojIGV4dHJhY3QgbnVjbGVvdGlkZSBkaXZlcnNpdHkgYW5kIGNvcnJlY3QgZm9yIHdpbmRvdyBzaXplCm5kIDwtIHB3c19zd0BudWMuZGl2ZXJzaXR5LndpdGhpbi81MDAwMAoKIyBtYWtlIGdyb3VwIG5hbWUgdmVjdG9yCmdyb3VwbmFtZXMgPC0gc29ydCh1bmlxdWUocG9wcyRncm91cCkpCiMgc2V0IHBvcHVsYXRpb24gbmFtZXMKY29sbmFtZXMobmQpIDwtIHBhc3RlMChncm91cG5hbWVzLCAiX3BpIikKCiMgZXh0cmFjdCBmc3QgdmFsdWVzCmZzdCA8LSB0KHB3c19zd0BudWMuRl9TVC5wYWlyd2lzZSkKCiMgZXh0cmFjdCBkeHkgLSBwYWlyd2lzZSBhYnNvbHV0ZSBudWNsZW90aWRlIGRpdmVyc2l0eQpkeHkgPC0gZ2V0LmRpdmVyc2l0eShwd3Nfc3csIGJldHdlZW4gPSBUKVtbMl1dLzUwMDAwCgojIGdldCBjb2x1bW4gbmFtZXMgCnggPC0gY29sbmFtZXMoZnN0KQp4IDwtIHN1YigicG9wMSIsIGdyb3VwbmFtZXNbMV0sIHgpCnggPC0gc3ViKCJwb3AyIiwgZ3JvdXBuYW1lc1syXSwgeCkKeCA8LSBzdWIoInBvcDMiLCBncm91cG5hbWVzWzNdLCB4KQp4IDwtIHN1YigiLyIsICJfIiwgeCkKCmNvbG5hbWVzKGZzdCk8LXBhc3RlMCgiZnN0XyIseCkKY29sbmFtZXMoZHh5KTwtcGFzdGUwKCJkeHlfIix4KQoKI2NvbWJpbmUgYWxsIGRhdGEKcHdzX2RhdGEgPC0gYXNfdGliYmxlKGRhdGEuZnJhbWUod2luZG93LCBuZCwgZnN0LCBkeHkpKQp3cml0ZS5jc3YocHdzX2RhdGEsIi4uL091dHB1dC9QQ0EvUFdTb25seV9jaHI4X3BvcGdlbm9tZV9zdGF0cy5jc3YiKQoKY29tYjwtY29tYm4oZ3JvdXBuYW1lcywgMikKY29tYjwtdChjb21iKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZHQ8LXB3c19kYXRhWywgYygibWlkIiwgcGFzdGUwKCJmc3RfIiwgcG9wMSwiXyIscG9wMikscGFzdGUwKCJkeHlfIixwb3AxLCJfIixwb3AyKSwgcGFzdGUwKHBvcDEsIl9waSIpLHBhc3RlMChwb3AyLCJfcGkiKSkgXQogICAgICAgIGNvbG5hbWVzKGR0KVsyOjNdPC1jKCJGc3QiLCJEeHkiKQogICAgCiAgICAgICAgZHRfZzwtZ2F0aGVyKGR0LCAtbWlkLCBrZXkgPSAic3RhdCIsIHZhbHVlID0gInZhbHVlIikKICAgICAgICBkdF9nJHN0YXQ8LWZhY3RvcihkdF9nJHN0YXQsIGxldmVscz1jKCJGc3QiLCJEeHkiLGNvbG5hbWVzKGR0KVs0XSwgY29sbmFtZXMoZHQpWzVdKSkKICAgICAgICBnZ3Bsb3QoZHRfZywgYWVzKG1pZC8xMF42LCB2YWx1ZSwgY29sb3VyID0gc3RhdCkpICsgZ2VvbV9saW5lKCkrCiAgICAgICAgICAgIGZhY2V0X2dyaWQoc3RhdH4uLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICAgICAgICAgIHhsYWIoIlBvc2l0aW9uIChNYikiKSt5bGFiKCcnKSsKICAgICAgICAgICAgdGhlbWVfbGlnaHQoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrZ2d0aXRsZShwYXN0ZTAoIkNocjggIixwb3AxLCIgdnMuIiwgcG9wMikpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobWlub3JfYnJlYWtzID0gc2VxKDEsIGNocjgsMSApKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyOF8iLHBvcDEsIiB2cy4iLCBwb3AyLCIucG5nIiksIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKICAgIH0KYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfRGl2ZXJzaXR5X3N0YXRzX2NocjhfR3JvdXAxIHZzLkdyb3VwMi5wbmcpICAKIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyOF9Hcm91cDEgdnMuR3JvdXAzLnBuZykgIAoKIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyOF9Hcm91cDIgdnMuR3JvdXAzLnBuZykKUG9zaXRpb24gMjNNYi1lbmQgc2hvd3MgaGlnaCBGc3QgYW1vbmcgZ3JvdXBzLgoKPGJyPgoKIyMjIEdlbm90eXBlIHBsb3QgZm9yIGVhY2ggeWVhciAgLSBpbnZlcnNpb24gaXMgbm90IGNsZWFybHkgdmlzaWJsZSAgCkNocjggaXMgc3VnZ2VzdGVkIHRvIGhhdmUgYSAncHV0YXRpdmUgaW52ZXJzaW9uJyBpbiBQZXRyb3UgZXQgYWwuIDIwMjEKCiFbXSguLi9PdXRwdXQvY2hyL0RQNzAwMC9jaHI4L1BXU29ubHlfUFdTOTZfY2hyOC5wbmcpe3dpZHRoPTMwJX0gCiFbXSguLi9PdXRwdXQvY2hyL0RQNzAwMC9jaHI4L1BXU29ubHlfUFdTMDdfY2hyOC5wbmcpe3dpZHRoPTMwJX0gCiFbXSguLi9PdXRwdXQvY2hyL0RQNzAwMC9jaHI4L1BXU29ubHlfUFdTMTdfY2hyOC5wbmcpe3dpZHRoPTMwJX0gCgojIyMgTWVhbiBGc3QgYmV0d2VlbiBncm91cHMgCgpgYGB7ciBlY2hvPUZBTFNFLCBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpjOGZzdDwtbWVsdChwd3NfZGF0YVssYygzLDc6OSldLCBpZC52YXJzPSJtaWQiKQpnZ3Bsb3QoYzhmc3QsIGFlcyh4PXZhcmlhYmxlLCB5PXZhbHVlLCBjb2xvcj12YXJpYWJsZSkpKwogICAgZ2VvbV9ib3hwbG90KCkrdGhlbWVfbGlnaHQoKSt4bGFiKCcnKSt5bGFiKCdGc3QnKSsKICAgIGdlb21fcG9pbnQoc3RhdD0ic3VtbWFyeSIsIGZ1bj0ibWVhbiIsIGNvbG9yPSJncmF5MzAiKQpnZ3NhdmUoIi4uL091dHB1dC9QQ0EvQ2g4X0ZzdF9iZXR3ZWVuM2dvdXBzLnBuZyIsZHBpPTMwMCwgd2lkdGggPSA2LCBoZWlnaHQ9NCkKbWVhbihwd3NfZGF0YSRmc3RfR3JvdXAxX0dyb3VwMikgIzAuMDMwODcwOTMKbWVhbihwd3NfZGF0YSRmc3RfR3JvdXAxX0dyb3VwMykgIzAuMTI4Mzk3NAptZWFuKHB3c19kYXRhJGZzdF9Hcm91cDJfR3JvdXAzKSAjMC4wNzc5OTc1NAoKYGBgCiFbXSguLi9PdXRwdXQvUENBL0NoOF9Gc3RfYmV0d2VlbjNnb3Vwcy5wbmcpe3dpZHRoPTUwJX0KCiMjIyBNZWFuIEZzdCBiZXR3ZWVuIGdyb3VwcyBvdmVyIHllYXJzICAKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiNjYWxjdWxhdGUgbWVhbiBGc3QgYmV0d2VlbiBncm91cHMgd2l0aGluIGVhY2ggeWVhcgpwd3MgPC0gcmVhZERhdGEoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5L1BXU29ubHlfY2hyOC8iLCBmb3JtYXQgPSAiVkNGIiwgaW5jbHVkZS51bmtub3duID0gVFJVRSwgRkFTVCA9IFRSVUUpCiNhc3NpZ24gZ3JvdXBzCnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BzPC1wb3BfaW5mb1twb3BfaW5mbyRwb3A9PSJQV1MiLF0KCnBvcHMkZ3JvdXA8LSJHcm91cDEiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBjOCRTYW1wbGVbYzgkZ3JvdXA9PSJHcm91cDIiXV08LSJHcm91cDIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBjOCRTYW1wbGVbYzgkZ3JvdXA9PSJHcm91cDMiXV08LSJHcm91cDMiCgpwb3BzJGlkPC1wYXN0ZTAocG9wcyRncm91cCwiLiIscG9wcyRZZWFyLkNvbGxlY3RlZCkKcG9wdWxhdGlvbnMyIDwtIHNwbGl0KHBvcHMkU2FtcGxlLCBwb3BzJGlkKQoKcHdzMjwtc2V0LnBvcHVsYXRpb25zKHB3cywgcG9wdWxhdGlvbnMyLCBkaXBsb2lkID0gVCkKcHdzX3N3MiA8LSBzbGlkaW5nLndpbmRvdy50cmFuc2Zvcm0ocHdzMiwgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKcHdzX3N3MiA8LSBkaXZlcnNpdHkuc3RhdHMocHdzX3N3MiwgcGkgPSBUUlVFKQpwd3Nfc3cyIDwtIEZfU1Quc3RhdHMocHdzX3N3MiwgbW9kZSA9ICJudWNsZW90aWRlIikKbmQyIDwtIHB3c19zdzJAbnVjLmRpdmVyc2l0eS53aXRoaW4vNTAwMDAKaWRuYW1lcyA8LSBuYW1lcyhwd3MyQHBvcHVsYXRpb25zKSMgc29ydCh1bmlxdWUocG9wcyRpZCkpCmNvbG5hbWVzKG5kMikgPC0gcGFzdGUwKGlkbmFtZXMsICJfcGkiKQoKZnN0MiA8LSB0KHB3c19zdzJAbnVjLkZfU1QucGFpcndpc2UpCmR4eTIgPC0gZ2V0LmRpdmVyc2l0eShwd3Nfc3cyLCBiZXR3ZWVuID0gVClbWzJdXS81MDAwMAoKIyBnZXQgY29sdW1uIG5hbWVzIAp4IDwtIGNvbG5hbWVzKGZzdDIpCmZvciAoaSBpbiAxOiBsZW5ndGgoaWRuYW1lcykpewogICAgeDwtc3ViKHBhc3RlMCgicG9wIixpLCIvIiksIHBhc3RlMChpZG5hbWVzW2ldLCJfIiksIHgpCiAgICB4PC1zdWIocGFzdGUwKCJwb3AiLGksIiQiKSwgcGFzdGUwKGlkbmFtZXNbaV0pLCB4KQp9CmNvbG5hbWVzKGZzdDIpPC1wYXN0ZTAoImZzdF8iLHgpCmNvbG5hbWVzKGR4eTIpPC1wYXN0ZTAoImR4eV8iLHgpCgojIGNyYXRlIHNsaWRpbmcgd2luZG93IGluZm8Kd2luZG93czwtcHdzX3N3MkByZWdpb24ubmFtZXMKd2luZG93czwtZ3N1YigiICIsIiIsIHdpbmRvd3MpCndpbmRvd3M8LWdzdWIoIjoiLCIiLHdpbmRvd3MpCndpbmRvd19zdGFydDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzFdKSkKd2luZG93X3N0b3A8LWFzLmludGVnZXIoc2FwcGx5KHdpbmRvd3MsIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAiLSIpKVsyXSkpCndpbmRvdzwtZGF0YS5mcmFtZShzdGFydCA9IHdpbmRvd19zdGFydCwgc3RvcCA9IHdpbmRvd19zdG9wLCAKICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IHdpbmRvd19zdGFydCArICh3aW5kb3dfc3RvcC13aW5kb3dfc3RhcnQpLzIpCgojY29tYmluZSBhbGwgZGF0YQpwd3NfZGF0YTIgPC0gYXNfdGliYmxlKGRhdGEuZnJhbWUod2luZG93LCBuZDIsIGZzdDIsIGR4eTIpKQpmc3RhbGw8LXB3c19kYXRhMlssYygzLCBncmVwKCJmc3QiLCBjb2xuYW1lcyhwd3NfZGF0YTIpKSldCmZzdG08LWRhdGEuZnJhbWUoRnN0PWNvbE1lYW5zKGZzdGFsbFssMjo2N10sIG5hLnJtPVQpKQpmc3RtJGdyb3VwQTwtc3Vic3RyKHJvd25hbWVzKGZzdG0pLCA1LDEwKQpmc3RtJGdyb3VwQjwtc3Vic3RyKHJvd25hbWVzKGZzdG0pLCAxNywyMikKZnN0bSR5ZWFyQTwtc3Vic3RyKHJvd25hbWVzKGZzdG0pLCAxMiwxNSkKZnN0bSR5ZWFyQjwtc3Vic3RyKHJvd25hbWVzKGZzdG0pLCAyNCwyNykKZnN0bSR5ZWFyPC0gYXBwbHkoZnN0bVssYygieWVhckEiLCJ5ZWFyQiIpXSwgMSwgZnVuY3Rpb24oeCkge2lmICh4WyJ5ZWFyQSJdPT14Wyd5ZWFyQiddKSB4WyJ5ZWFyQSJdCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBlbHNlIE5BfSkKCnBjb2xzPC1jKCIjZDdiNWQ4IiwiI2RmNjViMCIsIiNkZDFjNzciLCIjOTgwMDQzIikKZnN0bTI8LWZzdG1bIWlzLm5hKGZzdG0keWVhciksXQpmc3RtMiRjb21wPC1wYXN0ZTAoZnN0bTIkZ3JvdXBBLCIudnMuIixmc3RtMiRncm91cEIpCmdncGxvdChmc3RtMiwgYWVzKHg9Y29tcCwgeT1Gc3QsIGZpbGw9eWVhcikpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMSkpKwogICAgdGhlbWVfbGlnaHQoKSt4bGFiKCcnKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wY29scykKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU29ubHlfRnN0X2JldHdlZW4uZ3JvdXBzX2VhY2hZZWFyLnBuZyIsIHdpZHRoID0gNy41LCBoZWlnaHQgPSA1LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9Gc3RfYmV0d2Vlbi5ncm91cHNfZWFjaFllYXIucG5nKQpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpnZ3Bsb3QoZnN0bTIsIGFlcyh4PXllYXIsIHk9RnN0LCBjb2xvcj1jb21wLCBncm91cD1jb21wKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICBnZW9tX3BhdGggKCkrCiAgICB0aGVtZV9saWdodCgpK3hsYWIoJycpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGNvbHMpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X2NoOF9Gc3Rfb3ZlcnRpbWVfYW1vbmdHcm91cHMucG5nIiwgd2lkdGg9NiwgaGVpZ2h0PTQsIGRwaT0yMDApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X2NoOF9Gc3Rfb3ZlcnRpbWVfYW1vbmdHcm91cHMucG5nKQoKIyMjIENhbGN1bGF0ZSBoZXRlcm96eWdvc2l0eSBmb3IgZWFjaCBncm91cCBhcyBpbiBjaHIxNSAoJ0JveCAxJykKCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNDYWxjdWxhdGUgaGV0ZXJvenlnb3NpdHkgcGVyIHdpbmRvdyB1c2luZyBiY2Z0b29scyAoaGV0X3N0YXRzX1BXUzkxLnNoKQojZS5nLiAKCmJjZnRvb2xzIHN0YXRzIC1yIGNocjE1OjAtMjMwMDAwIC1zIC0gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXU29ubHk5MV9tYWYwNS52Y2YuZ3ogfCBncmVwICdeUFNDJyA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9QV1M5MS9QV1M5MV9zdGF0c18xCmJjZnRvb2xzIHN0YXRzIC1yIGNocjE1OjEwMDAwMC0yMDAwMDAgLXMgLSAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vUFdTb25seTkxX21hZjA1LnZjZi5neiB8IGdyZXAgJ15QU0MnID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL1BXUzkxL1BXUzkxX3N0YXRzXzIKI2V0Yy4uLgoKI2NhdCBhbGwgZmlsZXMgKGNhdEZpbGVzX1BXUzkxLnNoKQpmb3IgZiBpbiAqOyBkbyBzZWQgLWkgInMvJC9cdCRmLyIgJGY7IGRvbmUgCmNhdCAkKGxzIC10KSA+IFBXUzkxX3N0YXRzRmlsZQoKYGBgCgojIyMgUHJvY2VzcyB0aGUgYmNmdG9vbHMgc3RhdHMgZmlsZSB0byBvYnRhaW4gSG8gYW5kIEhlCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMjIFJlYWQgdGhlIHN0YXRzIGZpbGVzIGFuZCBjcmVhdGUgaGV0IHN1bW1hcnkKCiMgQ2FsY3VsYXRlIEhvIGFuZCBIZSBmcm9tIGJjZnRvb2xzIHN0YXRzIG91dHB1dCBmaWxlcyAoc3RhdHMgZnJvbSBQV1Nvbmx5IGZpbGVzKQpzZmlsZXM8LWxpc3QuZmlsZXMoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5LyIsIHBhdHRlcm49Il9jaHI4X3N0YXRzRmlsZSIpCkhldF9zdW08LWRhdGEuZnJhbWUoKQpmb3IgKGkgaW4gMTpsZW5ndGgoc2ZpbGVzKSl7CiAgICBkZjwtcmVhZC50YWJsZShwYXN0ZTAoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5LyIsIHNmaWxlc1tpXSksIHNlcD0iXHQiLCBoZWFkZXI9RikKICAgIHBuYW1lPC1nc3ViKCJfY2hyOF9zdGF0c0ZpbGUiLCcnLHNmaWxlc1tpXSkKICAgIHBuYW1lPC1nc3ViKCJQV1Nvbmx5XyIsJycsIHBuYW1lKQogICAgZGY8LWRmWyxjKDM6MTAsIDE0OjE1KV0KICAgIGNvbG5hbWVzKGRmKTwtYygiU2FtcGxlIiwiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIsICJuVHJhbnNpdGlvbnMiLCAiblRyYW5zdmVyc2lvbnMiLCJuSW5kZWxzIiwiYXZlcmFnZSBkZXB0aCIsIm5NaXNzaW5nIiwid2luZG93X25vIikKICAgIGRmJHA8LSgyKmRmJG5SZWZIb20rZGYkbkhldHMpLyhyb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKSoyKQogICAgZGYkcTwtKDIqZGYkbk5vblJlZkhvbStkZiRuSGV0cykvKHJvd1N1bXMoZGZbLGMoIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiKV0pKjIpCiAgICAKICAgIGRmJEhlPC0yKmRmJHAqZGYkcQogICAgZGYkSG88LWRmJG5IZXRzL3Jvd1N1bXMoZGZbLGMoIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiKV0pCiAgICAKICAgIGRmJEdyb3VwPC0iR3JvdXAxIgogICAgZGYkR3JvdXBbZGYkU2FtcGxlICVpbiUgZ3AyJFNhbXBsZV08LSJHcm91cDIiCiAgICBkZiRHcm91cFtkZiRTYW1wbGUgJWluJSBncDMkU2FtcGxlXTwtIkdyb3VwMyIKICAgIAogICAgSG88LWFnZ3JlZ2F0ZShkZlssIkhvIl0sIGJ5PWxpc3QoZGYkd2luZG93X25vLCBkZiRHcm91cCksIG1lYW4gKQogICAgSGU8LWFnZ3JlZ2F0ZShkZlssIkhlIl0sIGJ5PWxpc3QoZGYkd2luZG93X25vLGRmJEdyb3VwKSwgbWVhbiApCiAgICBoZXQ8LWNiaW5kKEhvLCBIZSR4KQogICAgY29sbmFtZXMoaGV0KTwtYygid2luZG93X2lkIiwiR3JvdXAiLCJIbyIsIkhlIikKICAgIHdyaXRlLmNzdihoZXQscGFzdGUwKCIuLi9PdXRwdXQvU3RhdHNfd2luZG93L1BXU29ubHlfY2hyOF9IZXRlcm96XyIscG5hbWUsIl9tYWYwNS5jc3YiKSkKICAgIAogICAgaGV0JHdpbmRvdzwtYXMuaW50ZWdlcihnc3ViKHBhc3RlMChwbmFtZSwiX3N0YXRzXyIpLCcnLGhldCR3aW5kb3dfaWQpKQogICAgaGV0JGxvYzwtInJlZ2lvbjEiCiAgICBoZXQkbG9jW2hldCR3aW5kb3c+MTY1XTwtInJlZ2lvbjIiCiAgICAKICAgIGdyb3VwSG88LWFnZ3JlZ2F0ZShoZXRbLCJIbyJdLCBieT1saXN0KGhldCRHcm91cCwgaGV0JGxvYyksIG1lYW4gLCBuYS5ybT1UKQogICAgY29sbmFtZXMoZ3JvdXBIbyk8LWMoIkdyb3VwIiwiUmVnaW9uIiwiSG8iKQogICAgZ3JvdXBIbyR5ZWFyPC1wbmFtZQogICAgSGV0X3N1bTwtcmJpbmQoSGV0X3N1bSxncm91cEhvKQp9Cgp3cml0ZS5jc3YoSGV0X3N1bSwgIi4uL091dHB1dC9TdGF0c193aW5kb3cvUFdTb25seV9jaHI4X0hldGVyb19ncm91cF9zdW1tYXJ5LmNzdiIpCmBgYAoKCiMjIyBDb21wYXJlIEhldGVyb3p5Z29zaXR5IGxldmVscyBhbW9uZyBncm91cHMgYW5kIGJldHdlZW4gcmVnaW9ucwpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGEgZmlndXJlCnBvcHM8LWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IikKCkhldDwtZGF0YS5mcmFtZSgpCmZvciAoaSBpbiAxOmxlbmd0aChwb3BzKSl7CiAgICBkZjwtcmVhZC5jc3YocGFzdGUwKCIuLi9PdXRwdXQvU3RhdHNfd2luZG93L1BXU29ubHlfY2hyOF9IZXRlcm96XyIscG9wc1tpXSwiX21hZjA1LmNzdiIpLCByb3cubmFtZXMgPSAxKQogICAgZGYkd2luZG93PC1hcy5pbnRlZ2VyKGdzdWIocGFzdGUwKHBvcHNbaV0sIl9zdGF0c18iKSwnJyxkZiR3aW5kb3dfaWQpKQogICAgZGYkbG9jPC0icmVnaW9uMSIKICAgIGRmJGxvY1tkZiR3aW5kb3c+MjMwXTwtInJlZ2lvbjIiCiAgICBkZiRwb3A8LXBvcHNbaV0KICAgIEhldDwtcmJpbmQoSGV0LGRmKSAgICAKfQoKZ2NvbHM8LWMoIiNGQjY4N0IiLCIjNDhBQkUzIiwiIzc1QkE3NiIpCkhldCRwb3A8LWZhY3RvcihIZXQkcG9wLCBsZXZlbHM9cG9wcykKY29sbmFtZXMoSGV0X3N1bSlbNF08LSJwb3AiCkhldF9zdW0kcG9wPC1mYWN0b3IoSGV0X3N1bSRwb3AsIGxldmVscz1wb3BzKQoKZ2dwbG90KCkrCiAgICBnZW9tX2JveHBsb3QoZGF0YT1IZXQsYWVzKHg9bG9jLCB5PUhvLCBjb2xvcj1Hcm91cCwgZmlsbD1Hcm91cCksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0wLjgpLG91dGxpZXIuYWxwaGEgPSAwLjYsIG91dGxpZXIuc2l6ZSA9IDEsd2lkdGg9MC43KSsKICAgIGdlb21fcG9pbnQoZGF0YT1IZXRfc3VtLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICBmYWNldF93cmFwKH5wb3ApKwogICAgdGhlbWVfbWluaW1hbCgpKwogICAgdGhlbWUocGFuZWwuZ3JpZC5tYWpvci54ID0gZWxlbWVudF9ibGFuaygpKSsKICAgIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IGMoMS41KSwgY29sb3I9ImdyYXk3MCIsc2l6ZT0wLjMpKwogICAgc2NhbGVfY29sb3JfbWFudWFsKHZhbHVlcz1nY29scykrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9cGFzdGUwKGdjb2xzLCAiNjYiKSkreGxhYignJykrZ2d0aXRsZSgiQ2hyOCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1NfQ2hyOF9Iby5pbi50d29yZWdpb25zLnBuZyIsICwgd2lkdGggPSA4LCBoZWlnaHQgPSA3LCBkcGk9MzAwKQpgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTX0NocjhfSG8uaW4udHdvcmVnaW9ucy5wbmcpCgojIyBDaHI4IGdyb3VwIHByb3BvcnRpb25zIGluIG90aGVyIHBvcHVsYXRpb25zIAohW10oLi4vT3V0cHV0L2Noci9jaDhfYWxsLnBuZyl7d2lkdGg9MzAlfSAhW10oLi4vT3V0cHV0L2Noci9jaDhfbm9UQi5wbmcpe3dpZHRoPTMwJX0KClRCIGNsdXN0ZXJlZCBpbiBvbmUgZ3JvdXAuIFRoZSByZXN0IGFyZSBpbiAzIGdyb3Vwcy4KCiMjIyBDcmVhdGUgYSBzdW1tYXJ5IG9mIGdyb3VwIHByb3BvcnRpb25zIGluIGVhY2ggeWVhciAgCgpgYGB7ciBlY2hvPVRSVUUsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CiNmcm9tIENocl9BbmFseXNpcy5SCmdwODwtcmVhZC5jc3YoIi4uL091dHB1dC9jaHIvRFA3MDAwL2NocjgvY2hyOF9QQ0Fncm91cHNfdXBkYXRlZC5jc3YiLCByb3cubmFtZXMgPSAxKQojIyBtYWtlIHN1cmUgZ3JvdXBpbmdzIGFyZSB0aGUgc2FtZSBmb3IgYWxsIHZzLiBQV1Nvbmx5CgpzZXRlcXVhbChncDgkU2FtcGxlW2dwOCRHcm91cD09Ikdyb3VwMSImZ3A4JHBvcD09IlBXUyJdLCBjOCRTYW1wbGVbYzgkR3JvdXA9PSJHcm91cDEiXSkKc2V0ZXF1YWwoZ3A4JFNhbXBsZVtncDgkR3JvdXA9PSJHcm91cDMiJmdwOCRwb3A9PSJQV1MiXSwgYzgkU2FtcGxlW2M4JEdyb3VwPT0iR3JvdXAzIl0pCgoKcG9wLnN1bTwtZ3A4ICU+JSBjb3VudChHcm91cCwgeXIucG9wKQoKcG9wLnN1bSR5ci5wb3A8LWZhY3Rvcihwb3Auc3VtJHlyLnBvcCwgbGV2ZWxzPWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikpCmdncGxvdChkYXRhPXBvcC5zdW0sIGFlcyh4PXlyLnBvcCwgeT1uLCBmaWxsPWZhY3RvcihHcm91cCkpKSsKICAgIGdlb21fYmFyKHBvc2l0aW9uPSJmaWxsIiwgc3RhdD0iaWRlbnRpdHkiLCBjb2xvcj0iZ3JheTMwIikrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2ZiYjRhZSIsIiNiM2NkZTMiLCIjY2NlYmM1IiksIGxhYmVscz1jKCJHcm91cDEiLCJHcm91cDIiLCJHcm91cDMiKSkrCiAgICB0aGVtZV9saWdodCgpKwogICAgeGxhYigiIikreWxhYigiUHJvcG9ydGlvbiIpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL0NocjhfM2dyb3Vwc19iYXJwbG90X2FsbFBvcHMucG5nIiwgd2lkdGggPSA4LCBoZWlnaHQgPSA1LjUsIGRwaT0zMDApCgoKYGBgCiFbXSguLi9PdXRwdXQvUENBL0NocjhfM2dyb3Vwc19iYXJwbG90X2FsbFBvcHMucG5nKXt3aWR0aD03MCV9CgoqICoqQ0EgYW5kIFBXUzE3IGhhdmUgbGFyZ2VyIHByb3BvcnRpb24gb2YgR3JvdXAyICh3aGljaCBoYXMgaGlnaGVyIEhvIHRoYW4gZ3JvdXAxIGluIHRoZSBoaWdoRnN0IHJlZ2lvbikqKgoKPGJyPgo8YnI+CgoKIyMjIExvb2sgYXQgdGhlIG92ZXJsYXAgb2YgaW5kaXZpZHVhbHMgaW4gR3JvdXAzL0dyb3VwMiBvZiBDaHIxNSBhbmQgQ2hyOCAoUFdTb25seSkKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KCgpjMTVnMzwtYzE1JFNhbXBsZVtjMTUkR3JvdXA9PSJHcm91cDMiXQpjOGczPC1jOCRTYW1wbGVbYzgkZ3JvdXA9PSJHcm91cDMiXQp4PC1saXN0KGNocjg9YzhnMyxjaHIxNT1jMTVnMykKcDM8LWdndmVubih4LCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDMiKQoKYzE1ZzI8LWMxNSRTYW1wbGVbYzE1JEdyb3VwPT0iR3JvdXAyIl0KYzhnMjwtYzgkU2FtcGxlW2M4JGdyb3VwPT0iR3JvdXAyIl0KeDI8LWxpc3QoY2hyOD1jOGcyLGNocjE1PWMxNWcyKQpwMjwtZ2d2ZW5uKHgyLCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDIiKQoKdmVubjwtZ2dkcmF3KCkrCiAgICAgICAgZHJhd19wbG90KHAyLHg9MCx5PTAsd2lkdGg9MC41LGhlaWdodD0xKSsKICAgICAgICBkcmF3X3Bsb3QocDMsMC41LDAsMC41LDEpKwogICAgICAgIGRyYXdfcGxvdF9sYWJlbCgiUFdTIiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDguY2gxNS5ncm91cF9vdmVybGFwLnBuZyIpLCBwbG90ID0gdmVubixiYXNlX3dpZHRoID0gNywgYmFzZV9oZWlnaHQgPSA1LCBkcGk9MzAwKSAgIApgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTX2NoOC5jaDE1Lmdyb3VwX292ZXJsYXAucG5nKQogKiAqKkNocjggYW5kIENocjE1IG91dGxpZXJzIChHcm91cDMgaW5kaXZpZHVhbHMpIGFyZSBub3QgdGhlIHNhbWUgKG9ubHkgMyBzYW1wbGVzIGJlbG9uZyB0byBncm91cDMgaW4gYm90aCkqKgoKCjxicj4KCiMgQ2hyMjAgICAKCiMjIExvb2sgYXQgUFdTIENocm9tb3NvbWUgMjA6IOKGkiBncm91cGVkIGludG8gMyAKCiogKipDbHVzdGVyaW5nIHBhdHRlcm5zIGFyZSBzbGlnaHRseSBkaWZmZXJlbnQgZm9yIFBXUyBvbmx5IHZzLiB3aXRoIG90aGVyIHBvcHVsYXRpb25zKiogIAoKKiBDQSBpbmRpdmlkdWFscyBoYXZlIGFuIGludmVyc2lvbiBhdCB0aGUgYmVnaW5uaW5nIG9mIHRoZSBjaHJvbW9zb21lCiogVEIgYWxzbyBzZXBhcmF0ZXMgaW50byAzIGdyb3VwcyAoZHVlIHRvIHRoZSBwcmVzZW5jZSBvZiB0aGUgaW52ZXJzaW9uKQoKIVtBbGwgcG9wdWxhdGlvbnNdKC4uL091dHB1dC9jaHIvY2hyMjBfYWxsLnBuZyl7d2lkdGg9NDAlfSAhW05vIFRCIF0oLi4vT3V0cHV0L2Noci9jaHIyMF9ub1RCLnBuZyl7d2lkdGg9NDAlfSAgICAKIVtdKC4uL091dHB1dC9jaHIvRFA3MDAwL2NocjIwL0NBX2NocjIwLnBuZyl7d2lkdGg9NDAlfSFbXSguLi9PdXRwdXQvY2hyL0RQNzAwMC9jaHIyMC9UQjkxX2NocjIwLnBuZyl7d2lkdGg9NDAlfQoKPGJyPgoKIyMjIFN0YXJ0IHdpdGggUFdTIG9ubHkKCmBgYHtyIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0UsIGV2YWw9RkFMU0V9CgojcHJvcG9ydGlvbiBvZiB5ZWFyIGluIGVhY2ggZ3JvdXAKY2gyMDwtcmVhZC5jc3YoIi4uL091dHB1dC9QQ0EvUFdTb25seV9wY2FfY2hyMjAuY3N2IikKZ3AxPC1jaDIwW2NoMjAkUEMxPjAuMDIsXQpncDMuMTwtY2gyMFtjaDIwJFBDMTwoLTAuMTUpJmNoMjAkUEMyPjAsXQpncDMuMjwtY2gyMFtjaDIwJFBDMTwoLTAuMDc1KSZjaDIwJFBDMjwwLF0KZ3AzPC1yYmluZChncDMuMSxncDMuMikKZ3AyPC1jaDIwWyEoY2gyMCRTYW1wbGUgJWluJSBjKGdwMSRTYW1wbGUsIGdwMyRTYW1wbGUpKSwgIF0KCnRhYmxlKGdwMSR5ZWFyKSAjOTkKIzE5OTEgMTk5NiAyMDA3IDIwMTcgCiMgIDI0ICAgMjggICAxOSAgIDI4IAp0YWJsZShncDIkeWVhcikgIzExMAojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgMjggICA0MCAgIDE4ICAgMjQgIAp0YWJsZShncDMkeWVhcikgIzkKIzE5OTEgMTk5NiAyMDA3IDIwMTcgCiMgICA2ICAgIDQgICAgOSAgICA0ICAKCmdwMSRncm91cDwtIkdyb3VwMSIKZ3AyJGdyb3VwPC0iR3JvdXAyIgpncDMkZ3JvdXA8LSJHcm91cDMiCmMyMDwtcmJpbmQoZ3AxLGdwMixncDMpCndyaXRlLmNzdihjMjAsICIuLi9PdXRwdXQvUENBL1BXU29ubHlfd2l0aC5ncm91cHNfcGNhX2NocjIwLmNzdiIpCgpwY29sczwtYygiI2Q3YjVkOCIsIiNkZjY1YjAiLCIjZGQxYzc3IiwiIzk4MDA0MyIpCmdncGxvdCgpKwogICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IGMyMCwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGZpbGwgPSBmYWN0b3IoeWVhciksIGNvbG9yID0gZmFjdG9yKHllYXIpLCBzaGFwZSA9IGZhY3Rvcih5ZWFyKSksIHNpemUgPSAzKSsKICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjMsMjUsMywyMSksIGd1aWRlPSJub25lIikrCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMChwY29scywiOTkiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXBjb2xzWzE6NF0pKwogICAgICAgIHhsYWIocGFzdGUoIlBDIDEiKSkrCiAgICAgICAgeWxhYihwYXN0ZSgiUEMgMiIpKSsKICAgICAgICB0aGVtZV9idygpKwogICAgICAgIGdndGl0bGUoIkNocjIwIikrCiAgICAgICAgZ3VpZGVzKHNoYXBlID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9YygyMywyNSwzLDIxKSksIGZpbGw9Z3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9cGFzdGUwKHBjb2xzLCI5OSIpKSkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSsKICAgICBzdGF0X2VsbGlwc2UoZGF0YT1jMjBbYzIwJGdyb3VwIT0iR3JvdXAyIixdLCBhZXMoeD1QQzEsIHk9UEMyLCBncm91cD1ncm91cCksIGNvbG9yPSJncmF5NTAiLCBzaXplPTAuMixsZXZlbD0wLjk5KSsKICAgICBnZW9tX2VsbGlwc2UoYWVzKHgwPS0wLjA1LCB5MD0wLjA4LCAgYW5nbGU9LTIwLjE1LCBhPTAuMjIsIGI9MC4wNSksIGNvbG9yPSJncmF5NTAiLCBzaXplPTAuMikrZ2VvbV9wYXRoKCkrCiAgICBhbm5vdGF0ZSgidGV4dCIsIHg9MC4wNSwgeT0wLjIsIGxhYmVsPSJHcm91cCAxIikrCiAgICBhbm5vdGF0ZSgidGV4dCIsIHg9LTAuMSwgeT0wLjMyLCBsYWJlbD0iR3JvdXAgMiIpKwogICAgYW5ub3RhdGUoInRleHQiLCB4PS0wLjIyLCB5PS0wLjIsIGxhYmVsPSJHcm91cCAzIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU29ubHlfQ2gyMF9QQ0Ffd2l0aEdyb3Vwcy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQuNSwgZHBpPTMwMCkKI1RCIGlzIGluIDEgZ3JvdXAKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfQ2gyMF9QQ0Ffd2l0aEdyb3Vwcy5wbmcpe3dpZHRoPTcwJX0KCiMjIyBQb3Jwb3J0aW9uIG9mIGVhY2ggZ3JvdXBzIHBlciB5ZWFyIAoKYGBge3IgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRSwgZXZhbD1GQUxTRX0KI0NyZWF0ZSBhIHN1bW1hcnkKY2gyMF9zdW1tYXJ5PC1kYXRhLmZyYW1lKHllYXI9YygxOTkxLDE5OTYsMjAwNywyMDE3KSkKY2gyMF9zdW1tYXJ5JEdyb3VwMTwtYXMudmVjdG9yKHRhYmxlKGdwMSR5ZWFyKSkKY2gyMF9zdW1tYXJ5JEdyb3VwMjwtYXMudmVjdG9yKHRhYmxlKGdwMiR5ZWFyKSkKY2gyMF9zdW1tYXJ5JEdyb3VwMzwtYXMudmVjdG9yKHRhYmxlKGdwMyR5ZWFyKSkKCmNoMjBfc3VtbWFyeSRHcm91cDE8LWFzLnZlY3Rvcih0YWJsZShjMjAkeWVhcltjMjAkZ3JvdXA9PSJHcm91cDEiXSkpCmNoMjBfc3VtbWFyeSRHcm91cDI8LWFzLnZlY3Rvcih0YWJsZShjMjAkeWVhcltjMjAkZ3JvdXA9PSJHcm91cDIiXSkpCmNoMjBfc3VtbWFyeSRHcm91cDM8LWFzLnZlY3Rvcih0YWJsZShjMjAkeWVhcltjMjAkZ3JvdXA9PSJHcm91cDMiXSkpCgojbWF0cml4IHRvIGJlIHRlc3RlZApYPC1jaDIwX3N1bW1hcnlbLDI6NF0Kcm93bmFtZXMoWCk8LWNoMjBfc3VtbWFyeSR5ZWFyCiNxdWljayBjaGktc3F1YXJlIHRlc3QgCmNoaXNxLnRlc3QoY2gyMF9zdW1tYXJ5WywyOjRdKQojWC1zcXVhcmVkID0gOS4wNjE5LCBkZiA9IDYsIHAtdmFsdWUgPSAwLjE3MDEKCmNoaXNxLnRlc3QoY2gyMF9zdW1tYXJ5W2MoMiwzKSwyOjRdKSAjUFdTOTUgdnMuIFBXUzE3CiNYLXNxdWFyZWQgPSA2LjU4MiwgZGYgPSAyLCBwLXZhbHVlID0gMC4wMzcyMgojYm9uZmVycm9uaSBjb3JyZWN0aW9uIDAuMDUvMTI9IDAuMDA0MTY2NjY3CmxpYnJhcnkoY2hpc3EucG9zdGhvYy50ZXN0KQojUnVuIHBvc3QtaG9jIGFuYWx5c2lzCmNoaXNxLnBvc3Rob2MudGVzdCh0KFgpLCBtZXRob2QgPSAiYm9uZmVycm9uaSIpCiMgRGltZW5zaW9uICAgICBWYWx1ZSAgICAgICAxOTkxICAgICAgIDE5OTYgICAgICAgMjAwNyAgICAgICAyMDE3CiMxICAgIEdyb3VwMSBSZXNpZHVhbHMgLTAuMjI5OTExOCAtMC43ODE2MTI0IC0wLjIwOTUxNjQgIDEuMjcyODc5MgojMiAgICBHcm91cDEgIHAgdmFsdWVzICAxLjAwMDAwMDAgIDEuMDAwMDAwMCAgMS4wMDAwMDAwICAxLjAwMDAwMDAKIzMgICAgR3JvdXAyIFJlc2lkdWFscyAgMC4xNTE4MjI4ICAxLjY2NjAyMDcgLTEuMjU2NTY0MCAtMC43ODQwNDE2CiM0ICAgIEdyb3VwMiAgcCB2YWx1ZXMgIDEuMDAwMDAwMCAgMS4wMDAwMDAwICAxLjAwMDAwMDAgIDEuMDAwMDAwMAojNSAgICBHcm91cDMgUmVzaWR1YWxzICAwLjEyNjgzNzEgLTEuNDkwMDg4NSAgMi40NDYyOTQ3IC0wLjc5NjYzNDUKIzYgICAgR3JvdXAzICBwIHZhbHVlcyAgMS4wMDAwMDAwICAxLjAwMDAwMDAgIDAuMTczMjAwMCAgMS4wMDAwMDAwCgpjMjBtPC1tZWx0KGNoMjBfc3VtbWFyeSwgaWQudmFycz0ieWVhciIpCmdncGxvdChjMjBtLCBhZXMoeD1mYWN0b3IoeWVhciksIHk9dmFsdWUsIGZpbGw9dmFyaWFibGUpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC41LCBjb2xvcj0iZ3JheTQwIixwb3NpdGlvbiA9ICJmaWxsIikrCiAgICB0aGVtZV9saW5lZHJhdygpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYigiUHJvcG9ydGlvbiBvZiBpbmRpdmlkdWFscyIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmYmI0YWUiLCIjYjNjZGUzIiwiI2NjZWJjNSIpKSt4bGFiKCJZZWFyIikrZ2d0aXRsZSgiUFdTIENocjIwIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU19jaDIwX3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfY2gyMF9wcm9wX2luZGl2aV9pbjNncm91cHMucG5nKXt3aWR0aD03MCV9CgojIyMgQ2FsY3VhbHRlIEZzdC9EeHkgYmV0d2VlbiBHcm91cHMgYWNyb3NzIHllYXJzIHdpdGhpbiBjaHIyMAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQojIHJlYWQgY2hyMjAgZnJvbSB0aGUgJ1BXU29ubHknIGZpbGUKIyBTdWJzZXQgVkNGIGJ5IGNocjIwIAojYmNmdG9vbHMgdmlldyAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X05TMC41X21hZjA1LnZjZi5neiAtLXJlZ2lvbnMgY2hyMjAgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2gyMF9tYWYwNS52Y2YKCgpwd3MgPC0gcmVhZERhdGEoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5L1BXU29ubHlfY2hyMjAvIiwgZm9ybWF0ID0gIlZDRiIsIGluY2x1ZGUudW5rbm93biA9IFRSVUUsIEZBU1QgPSBUUlVFKQpwb3BfaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wczwtcG9wX2luZm9bcG9wX2luZm8kcG9wPT0iUFdTIixdCgojYXNzaWduIGdyb3Vwcwpwb3BzJGdyb3VwPC0iR3JvdXAxIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgZ3AyJFNhbXBsZV08LSJHcm91cDIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBncDMkU2FtcGxlXTwtIkdyb3VwMyIKcG9wdWxhdGlvbnMgPC0gc3BsaXQocG9wcyRTYW1wbGUsIHBvcHMkZ3JvdXApCnB3czwtc2V0LnBvcHVsYXRpb25zKHB3cywgcG9wdWxhdGlvbnMsIGRpcGxvaWQgPSBUKQoKIyBzZXQgdGhlIGNocm9tb3NvbWUgc2l6ZQpjaHJzaXplPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25ld192Y2YvY2hyX3NpemVzLmJlZCIpCmNocjwtY2hyc2l6ZSRWM1tjaHJzaXplJFYxPT0iY2hyMjAiXQoKIyBtYWtlIGEgc2xpZGluZyB3aW5kb3cgZGF0YXNldApwd3Nfc3cgPC0gc2xpZGluZy53aW5kb3cudHJhbnNmb3JtKHB3cywgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKIyBjcmF0ZSBzbGlkaW5nIHdpbmRvdyBpbmZvCndpbmRvd3M8LXB3c19zd0ByZWdpb24ubmFtZXMKd2luZG93czwtZ3N1YigiICIsIiIsIHdpbmRvd3MpCndpbmRvd3M8LWdzdWIoIjoiLCIiLHdpbmRvd3MpCndpbmRvd19zdGFydDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzFdKSkKd2luZG93X3N0b3A8LWFzLmludGVnZXIoc2FwcGx5KHdpbmRvd3MsIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAiLSIpKVsyXSkpCndpbmRvdzwtZGF0YS5mcmFtZShzdGFydCA9IHdpbmRvd19zdGFydCwgc3RvcCA9IHdpbmRvd19zdG9wLCAKICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IHdpbmRvd19zdGFydCArICh3aW5kb3dfc3RvcC13aW5kb3dfc3RhcnQpLzIpCgojY2FsY3VsYXRlIGRpdmVyc2l0eSBzdGF0cwpwd3Nfc3cgPC0gZGl2ZXJzaXR5LnN0YXRzKHB3c19zdywgcGkgPSBUUlVFKQpwd3Nfc3cgPC0gRl9TVC5zdGF0cyhwd3Nfc3csIG1vZGUgPSAibnVjbGVvdGlkZSIpCiMgZXh0cmFjdCBudWNsZW90aWRlIGRpdmVyc2l0eSBhbmQgY29ycmVjdCBmb3Igd2luZG93IHNpemUKbmQgPC0gcHdzX3N3QG51Yy5kaXZlcnNpdHkud2l0aGluLzUwMDAwCiMgbWFrZSBncm91cCBuYW1lIHZlY3RvciBhbmQgcmVuYW1lIHRoZSBjb2x1bW5zCmdyb3VwbmFtZXMgPC0gc29ydCh1bmlxdWUocG9wcyRncm91cCkpCmNvbG5hbWVzKG5kKSA8LSBwYXN0ZTAoZ3JvdXBuYW1lcywgIl9waSIpCiMgZXh0cmFjdCBmc3QgdmFsdWVzCmZzdCA8LSB0KHB3c19zd0BudWMuRl9TVC5wYWlyd2lzZSkKIyBleHRyYWN0IGR4eSAtIHBhaXJ3aXNlIGFic29sdXRlIG51Y2xlb3RpZGUgZGl2ZXJzaXR5CmR4eSA8LSBnZXQuZGl2ZXJzaXR5KHB3c19zdywgYmV0d2VlbiA9IFQpW1syXV0vNTAwMDAKIyBzZXQgdGhlIGNvbHVtbiBuYW1lcyAKeCA8LSBjb2xuYW1lcyhmc3QpCnggPC0gc3ViKCJwb3AxIiwgZ3JvdXBuYW1lc1sxXSwgeCkKeCA8LSBzdWIoInBvcDIiLCBncm91cG5hbWVzWzJdLCB4KQp4IDwtIHN1YigicG9wMyIsIGdyb3VwbmFtZXNbM10sIHgpCnggPC0gc3ViKCIvIiwgIl8iLCB4KQoKY29sbmFtZXMoZnN0KTwtcGFzdGUwKCJmc3RfIix4KQpjb2xuYW1lcyhkeHkpPC1wYXN0ZTAoImR4eV8iLHgpCgojY29tYmluZSBhbGwgZGF0YQpwd3NfZGF0YSA8LSBhc190aWJibGUoZGF0YS5mcmFtZSh3aW5kb3csIG5kLCBmc3QsIGR4eSkpCndyaXRlLmNzdihwd3NfZGF0YSwiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X2NocjIwX3BvcGdlbm9tZV9zdGF0cy5jc3YiKQoKY29tYjwtY29tYm4oZ3JvdXBuYW1lcywgMikKY29tYjwtdChjb21iKQpmb3IgKGkgaW4gMTogbnJvdyhjb21iKSl7CiAgICAgICAgcG9wMTwtY29tYltpLDFdCiAgICAgICAgcG9wMjwtY29tYltpLDJdCiAgICAgICAgZHQ8LXB3c19kYXRhWywgYygibWlkIiwgcGFzdGUwKCJmc3RfIiwgcG9wMSwiXyIscG9wMikscGFzdGUwKCJkeHlfIixwb3AxLCJfIixwb3AyKSwgcGFzdGUwKHBvcDEsIl9waSIpLHBhc3RlMChwb3AyLCJfcGkiKSkgXQogICAgICAgIGNvbG5hbWVzKGR0KVsyOjNdPC1jKCJGc3QiLCJEeHkiKQogICAgCiAgICAgICAgZHRfZzwtZ2F0aGVyKGR0LCAtbWlkLCBrZXkgPSAic3RhdCIsIHZhbHVlID0gInZhbHVlIikKICAgICAgICBkdF9nJHN0YXQ8LWZhY3RvcihkdF9nJHN0YXQsIGxldmVscz1jKCJGc3QiLCJEeHkiLGNvbG5hbWVzKGR0KVs0XSwgY29sbmFtZXMoZHQpWzVdKSkKICAgICAgICBnZ3Bsb3QoZHRfZywgYWVzKG1pZC8xMF42LCB2YWx1ZSwgY29sb3VyID0gc3RhdCkpICsgZ2VvbV9saW5lKCkrCiAgICAgICAgICAgIGZhY2V0X2dyaWQoc3RhdH4uLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICAgICAgICAgIHhsYWIoIlBvc2l0aW9uIChNYikiKSt5bGFiKCcnKSsKICAgICAgICAgICAgdGhlbWVfbGlnaHQoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrZ2d0aXRsZShwYXN0ZTAoIkNocjIwICIscG9wMSwiIHZzLiIsIHBvcDIpKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IHNlcSgxLCBjaHIsMSApKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyMjBfIixwb3AxLCIgdnMuIiwgcG9wMiwiLnBuZyIpLCB3aWR0aCA9IDksIGhlaWdodCA9IDQsIGRwaT0xNTApCiAgICB9CmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X0RpdmVyc2l0eV9zdGF0c19jaHIyMF9Hcm91cDEgdnMuR3JvdXAyLnBuZyl7d2lkdGg9NzUlfQoKIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyMjBfR3JvdXAxIHZzLkdyb3VwMy5wbmcpe3dpZHRoPTc1JX0KIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyMjBfR3JvdXAyIHZzLkdyb3VwMy5wbmcpe3dpZHRoPTc1JX0KCiAqKuKAoiBXaGF0IHNlcGFyYXRlcyBQV1MgZ3JvdXBzIGFyZSBub3QgdGhlIGludmVyc2lvbiwgYnV0IHRoZSBlbmQgb2YgdGhlIGNob3JvbXNvbWUgKD4yMS44TWIpICoqCjxicj4KCiMjIyBDb21wYXJlIHRoZSBoZXRlcm96eWdvc2l0eSBvZiB0aGUgcmVnaW9uIG9mIGludGVyZXN0IChyZWdpb24gMikKCmBgYHtSIGV2YWw9RkFMU0V9CiMgMSBkaXZpZGUgdGhlIHZjZiBpbnRvIDMgZ3JvdXBzIC1jcmVhdGUgdGhlIHNhbXBsZSBsaXN0IGZvciBlYWNoIGdyb3VwCndyaXRlLnRhYmxlKGdwMSRTYW1wbGUsICIuLi9EYXRhL25ld192Y2YvUFdTb25seS9wd3NjaDIwX2dyb3VwMS50eHQiLCBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCndyaXRlLnRhYmxlKGdwMiRTYW1wbGUsICIuLi9EYXRhL25ld192Y2YvUFdTb25seS9wd3NjaDIwX2dyb3VwMi50eHQiLCBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCndyaXRlLnRhYmxlKGdwMyRTYW1wbGUsICIuLi9EYXRhL25ld192Y2YvUFdTb25seS9wd3NjaDIwX2dyb3VwMy50eHQiLCBxdW90ZSA9IEYsIHJvdy5uYW1lcyA9IEYsIGNvbC5uYW1lcyA9IEYpCmBgYAoKYGBge2Jhc2ggZXZhbD1GQUxTRSwgaW5jbHVkZT1UUlVFfQojQ2FsY3VsYXRlIGhldGVyb3p5Z29zaXR5IHBlciB3aW5kb3cgdXNpbmcgYmNmdG9vbHMgCiMgMS4gc3Vic2V0IFZDRiBieSBjaHIyMCAoaGV0X3N0YXRzX1BXUy5jaDIwLnNoKQpiY2Z0b29scyB2aWV3ICAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfTlMwLjVfbWFmMDUudmNmLmd6IC0tcmVnaW9ucyBjaHIyMCA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9jaDIwX21hZjA1LnZjZgpiZ3ppcCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2gyMF9tYWYwNS52Y2YKYmNmdG9vbHMgaW5kZXggL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NoMjBfbWFmMDUudmNmLmd6CgojMi4gc3Vic2V0IGJ5IGdyb3VwcyAoVGhpcyBwcm9jZXNzIGNhbiBiZSBkb25lIGluIFIgdG8gZ3JvdXAgaW5kaXZpZHVhbHMpCmJjZnRvb2xzIHZpZXcgLU96IC1TIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9wd3NjaDIwX2dyb3VwMS50eHQgLS10aHJlYWRzIDE2IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9jaDIwX21hZjA1LnZjZi5neiA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9jaHIyMF9ncm91cDFfbWFmMDUudmNmLmd6IApiY2Z0b29scyB2aWV3IC1PeiAtUyAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vcHdzY2gyMF9ncm91cDIudHh0IC0tdGhyZWFkcyAxNiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2gyMF9tYWYwNS52Y2YuZ3ogPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2hyMjBfZ3JvdXAyX21hZjA1LnZjZi5neiAKYmNmdG9vbHMgdmlldyAtT3ogLVMgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL3B3c2NoMjBfZ3JvdXAzLnR4dCAtLXRocmVhZHMgMTYgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NoMjBfbWFmMDUudmNmLmd6ID4gL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NocjIwX2dyb3VwM19tYWYwNS52Y2YuZ3ogCgpiY2Z0b29scyBpbmRleCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2hyMjBfZ3JvdXAzX21hZjA1LnZjZi5neiAKYmNmdG9vbHMgaW5kZXggL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NocjIwX2dyb3VwMl9tYWYwNS52Y2YuZ3ogCmJjZnRvb2xzIGluZGV4IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9jaHIyMF9ncm91cDFfbWFmMDUudmNmLmd6IAoKIzMuIFJ1biBoZXRfc3RhdHMyMGdyb3VwMS5zaCB0byBjYWxjdWxhdGUgaGV0IGluIHdpbmRvd3MKIzQuIGNhdCBhbGwgd2luZG93cyBpbiB0byBvbmUgZmlsZQpkIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvcG9wdWxhdGlvbi9jaDIwZ3JvdXAxLwpmb3IgZiBpbiAqOyBkbyBzZWQgLWkgInMvJC9cdCRmLyIgJGY7IGRvbmUgCmNhdCAkKGxzIC10KSA+IHB3c19jaDIwX2dyb3VwMV9zdGF0c0ZpbGUKY2QgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9wb3B1bGF0aW9uL2NoMjBncm91cDIvCmZvciBmIGluICo7IGRvIHNlZCAtaSAicy8kL1x0JGYvIiAkZjsgZG9uZSAKY2F0ICQobHMgLXQpID4gcHdzX2NoMjBfZ3JvdXAyX3N0YXRzRmlsZQpjZCAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL3BvcHVsYXRpb24vY2gyMGdyb3VwMy8KZm9yIGYgaW4gKjsgZG8gc2VkIC1pICJzLyQvXHQkZi8iICRmOyBkb25lIApjYXQgJChscyAtdCkgPiBwd3NfY2gyMF9ncm91cDNfc3RhdHNGaWxlCmBgYAoKCiMjIyBQcm9jZXNzIHRoZSBzdGF0cyBmaWxlIHRvIGNhbGN1bGF0ZSBIbyBhbmQgSGUKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFLCBldmFsPUZBTFNFfQojIENhbGN1bGF0ZSBIbyBhbmQgSGUgZnJvbSBiY2Z0b29scyBzdGF0cyBvdXRwdXQgZmlsZXMgKHN0YXRzIGZyb20gUFdTb25seSBmaWxlcykKc2ZpbGVzPC1saXN0LmZpbGVzKCIuLi9EYXRhL25ld192Y2YvUFdTb25seS8iLCBwYXR0ZXJuPXBhc3RlMCgiX2NoMjBfZ3JvdXBcXGRfc3RhdHNGaWxlIikpCgoKaG88LSBkYXRhLmZyYW1lKCkKZm9yIChpIGluIDE6bGVuZ3RoKHNmaWxlcykpewogICAgZGY8LXJlYWQudGFibGUocGFzdGUwKCIuLi9EYXRhL25ld192Y2YvUFdTb25seS8iLCBzZmlsZXNbaV0pLCBzZXA9Ilx0IiwgaGVhZGVyPUYpCiAgICBwbmFtZTwtcGFzdGUwKCJncm91cCIsaSkKICAgIGRmPC1kZlssYygzOjEwLCAxNDoxNSldCiAgICBjb2xuYW1lcyhkZik8LWMoIlNhbXBsZSIsIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiLCAiblRyYW5zaXRpb25zIiwgIm5UcmFuc3ZlcnNpb25zIiwibkluZGVscyIsImF2ZXJhZ2UgZGVwdGgiLCJuTWlzc2luZyIsIndpbmRvd19ubyIpCiAgICBkZiRwPC0oMipkZiRuUmVmSG9tK2RmJG5IZXRzKS8ocm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkqMikKICAgIGRmJHE8LSgyKmRmJG5Ob25SZWZIb20rZGYkbkhldHMpLyhyb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKSoyKQogICAgCiAgICBkZiRIZTwtMipkZiRwKmRmJHEKICAgIGRmJEhvPC1kZiRuSGV0cy9yb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKQogICAgCiAgICBkZiRHcm91cDwtcGFzdGUwKCJHcm91cCIsaSkKICAgIGhvPC1yYmluZChkZixobykKfQpIbzwtYWdncmVnYXRlKGhvWywiSG8iXSwgYnk9bGlzdChobyR3aW5kb3dfbm8saG8kR3JvdXApLCBtZWFuICkKSGU8LWFnZ3JlZ2F0ZShob1ssIkhlIl0sIGJ5PWxpc3QoaG8kd2luZG93X25vLGhvJEdyb3VwKSwgbWVhbiApCmhldDwtY2JpbmQoSG8sIEhlJHgpCmNvbG5hbWVzKGhldCk8LWMoIndpbmRvd19pZCIsIkdyb3VwIiwiSG8iLCJIZSIpCndyaXRlLmNzdihoZXQscGFzdGUwKCIuLi9PdXRwdXQvU3RhdHNfd2luZG93L1BXU29ubHlfY2hyMjBfSGV0ZXJvX2J5Z3JvdXBfbWFmMDUuY3N2IikpCiAgICAKaGV0JHdpbmRvdzwtYXMuaW50ZWdlcihnc3ViKHBhc3RlMCgicHdzX2NoMjBfZ3JvdXBcXGRfbWFmMDVfc3RhdHNfIiksJycsaGV0JHdpbmRvd19pZCkpCmhldCRsb2M8LSJyZWdpb24xIgpoZXQkbG9jW2hldCR3aW5kb3c+MjE1XTwtInJlZ2lvbjIiCiAgICAKZ3JvdXBIbzwtYWdncmVnYXRlKGhldFssIkhvIl0sIGJ5PWxpc3QoaGV0JEdyb3VwLCBoZXQkbG9jKSwgbWVhbiAsIG5hLnJtPVQpCmNvbG5hbWVzKGdyb3VwSG8pPC1jKCJHcm91cCIsIlJlZ2lvbiIsIkhvIikKd3JpdGUuY3N2KGdyb3VwSG8sICIuLi9PdXRwdXQvU3RhdHNfd2luZG93L1BXU29ubHlfY2hyMjBfSGV0ZXJvX2dyb3VwX3N1bW1hcnkuY3N2IikKYGBgCgojIyMgQ29tcGFyZSBIZXRlcm96eWdvc2l0eSBsZXZlbHMgYW1vbmcgZ3JvdXBzIGFuZCBiZXR3ZWVuIHJlZ2lvbnMKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI0NyZWF0ZSBhIGZpZ3VyZQpnY29sczwtYygiI0ZCNjg3QiIsIiM0OEFCRTMiLCIjNzVCQTc2IikKZ2dwbG90KCkrCiAgICBnZW9tX2JveHBsb3QoZGF0YT1oZXQsYWVzKHg9bG9jLCB5PUhvLCBjb2xvcj1Hcm91cCwgZmlsbD1Hcm91cCksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0wLjgpLG91dGxpZXIuYWxwaGEgPSAwLjYsIG91dGxpZXIuc2l6ZSA9IDEsd2lkdGg9MC43KSsKICAgIGdlb21fcG9pbnQoZGF0YT1ncm91cEhvLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygxLjUpLCBjb2xvcj0iZ3JheTcwIixzaXplPTAuMykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdjb2xzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoZ2NvbHMsICI2NiIpKSt4bGFiKCcnKStnZ3RpdGxlKCJDaHIyMCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1NfQ2hyMjBfSG8uaW4udHdvcmVnaW9ucy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0zMDApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfQ2hyMjBfSG8uaW4udHdvcmVnaW9ucy5wbmcpe3dpZHRoPTYwJX0gIAoKIyMjIExvb2sgYXQgdGhlIG92ZXJsYXAgb2YgaW5kaXZpZHVhbHMgaW4gR3JvdXAzL0dyb3VwMiBhbW9uZyBDaHIyMCwgQ2hyMTUgYW5kIENocjggKFBXU29ubHkpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojY2gxNSBhZG4gY2g4IGdyb3VwaW5ncyBhcmUgdGhlIHNhbWUgZm9yIFBXU29ubHkgYW5kIFBXUytvdGhlciBwb3BzCmMxNTwtcmVhZC5jc3YoIi4uL091dHB1dC9QQ0EvY2hyMTVfUENBZ3JvdXBzLmNzdiIsIHJvdy5uYW1lcyA9IDEpCmMxNTwtYzE1W2MxNSRwb3A9PSJQV1MiLF0KYzg8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL1BXU29ubHlfd2l0aC5ncm91cHNfcGNhX2NocjguY3N2Iiwgcm93Lm5hbWVzID0gMSkKCmMxNWczPC1jMTUkU2FtcGxlW2MxNSRHcm91cD09Ikdyb3VwMyJdCmM4ZzM8LWM4JFNhbXBsZVtjOCRncm91cD09Ikdyb3VwMyJdCmMyMGczPC1jMjAkU2FtcGxlW2MyMCRncm91cD09Ikdyb3VwMyJdCng8LWxpc3QoY2hyOD1jOGczLGNocjE1PWMxNWczLCBjaHIyMD1jMjBnMykKcDM8LWdndmVubih4LCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDMiKQoKYzE1ZzI8LWMxNSRTYW1wbGVbYzE1JEdyb3VwPT0iR3JvdXAyIl0KYzhnMjwtYzgkU2FtcGxlW2M4JGdyb3VwPT0iR3JvdXAyIl0KYzIwZzI8LWMyMCRTYW1wbGVbYzIwJGdyb3VwPT0iR3JvdXAyIl0KeDI8LWxpc3QoY2hyOD1jOGcyLGNocjE1PWMxNWcyLCBjaHIyMD1jMjBnMikKcDI8LWdndmVubih4MiwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAyIikKCnZlbm48LWdnZHJhdygpKwogICAgICAgIGRyYXdfcGxvdChwMix4PTAseT0wLHdpZHRoPTAuNSxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAzLDAuNSwwLDAuNSwxKSsKICAgICAgICBkcmF3X3Bsb3RfbGFiZWwoIlBXUyIsIHg9LTAuMDEsIHk9MC45NSwgc2l6ZSA9IDE1KQpzYXZlX3Bsb3QoZmlsZW5hbWUgPXBhc3RlMCgiLi4vT3V0cHV0L1BDQS9QV1NfY2g4LjE1LjIwLmdyb3VwX292ZXJsYXAucG5nIiksIHBsb3QgPSB2ZW5uLGJhc2Vfd2lkdGggPSA3LCBiYXNlX2hlaWdodCA9IDUsIGRwaT0zMDApICAgCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfY2g4LjE1LjIwLmdyb3VwX292ZXJsYXAucG5nKQoKPGJyPgoKIyMgQ2hyMjAgZ3JvdXBzIGFjcm9zcyBhbGwgcG9wdWxhdGlvbnMKCiFbXSguLi9PdXRwdXQvY2hyL2NocjIwX25vVEIucG5nKXt3aWR0aD00MCV9IVtdKC4uL091dHB1dC9jaHIvY2gyMF9QV1MucG5nKXt3aWR0aD00MCV9CgojIyMgQ29tcGFyZSAzIGdyb3VwcyBzZXBhcmF0ZWQgYnkgUEMxICgnSW52ZXJzaW9uIEdyb3B1cycpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQoKI3Byb3BvcnRpb24gb2YgeWVhciBpbiBlYWNoIGdyb3VwCmNocjIwPC1yZWFkLmNzdigiLi4vT3V0cHV0L2Noci9EUDcwMDAvY2hyMjBfUENBZ3JvdXBzLmNzdiIpCiNncm91cDMgaXMgZ3JvdXAxICgxPT10aGUgbW9zdCBtYWpvcml0eSBpbiBuZXcgZ3JvdXBpbmcpCmNocjIwJEdyb3VwW2NocjIwJEdyb3VwPT0xXTwtIkdyb3VwMyIKY2hyMjAkR3JvdXBbY2hyMjAkR3JvdXA9PTNdPC0iR3JvdXAxIgpjaHIyMCRHcm91cFtjaHIyMCRHcm91cD09Ml08LSJHcm91cDIiCgpjaHIyMF9zdW08LWRhdGEuZnJhbWUodGFibGUoY2hyMjAkR3JvdXAsY2hyMjAkeXIucG9wKSkKY29sbmFtZXMoY2hyMjBfc3VtKTwtYygiR3JvdXAiLCJ5ci5wb3AiLCJGcmVxIikKCmNocjIwX3N1bSR5ci5wb3A8LWZhY3RvcihjaHIyMF9zdW0keXIucG9wLCBsZXZlbHM9YygiUFdTOTEiLCJQV1M5NiIsIlBXUzA3IiwiUFdTMTciLCJTUzk2IiwiU1MwNiIsIlNTMTciLCJCQzE3IiwiV0ExNyIsIkNBMTciKSkKZ2dwbG90KGNocjIwX3N1bSwgYWVzKHg9eXIucG9wLCB5PUZyZXEsIGZpbGw9R3JvdXApKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC44LCBjb2xvcj0iZ3JheTQwIixwb3NpdGlvbiA9ICJmaWxsIikrCiAgICB0aGVtZV9saW5lZHJhdygpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYigiUHJvcG9ydGlvbiBvZiBpbmRpdmlkdWFscyIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWMoIiNmYmI0YWUiLCIjYjNjZGUzIiwiI2NjZWJjNSIpKSt4bGFiKCIiKStnZ3RpdGxlKCJDaHIyMCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9DaDIwX3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQsIGRwaT0zMDApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9DaDIwX3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmcpe3dpZHRoPTcwJX0KCiMjIyBDYWxjdWFsdGUgRnN0IGJldHdlZW4gR3JvdXBzIHdpdGhpbiBjaHIyMCBmb3IgYWxsIHBvcHMgKGV4Y2VwdCBUQikKCmBgYHtyIGVjaG89VFJVRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQpwaCA8LSByZWFkRGF0YSgiLi4vRGF0YS9uZXdfdmNmL2NoMjAvIiwgZm9ybWF0ID0gIlZDRiIsIGluY2x1ZGUudW5rbm93biA9IFRSVUUsIEZBU1QgPSBUUlVFKQpwb3BfaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wczwtcG9wX2luZm9bcG9wX2luZm8kcG9wIT0iVEIiLF0KCiNhc3NpZ24gZ3JvdXBzCnBvcHMkZ3JvdXA8LSJHcm91cDEiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBjaHIyMCRTYW1wbGVbY2hyMjAkR3JvdXA9PSJHcm91cDIiXV08LSJHcm91cDIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBjaHIyMCRTYW1wbGVbY2hyMjAkR3JvdXA9PSJHcm91cDMiXV0gPC0iR3JvdXAzIgpwb3B1bGF0aW9ucyA8LSBzcGxpdChwb3BzJFNhbXBsZSwgcG9wcyRncm91cCkKcGg8LXNldC5wb3B1bGF0aW9ucyhwaCwgcG9wdWxhdGlvbnMsIGRpcGxvaWQgPSBUKQoKIyBzZXQgdGhlIGNocm9tb3NvbWUgc2l6ZQpjaHJzaXplPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25ld192Y2YvY2hyX3NpemVzLmJlZCIpCmNocjwtY2hyc2l6ZSRWM1tjaHJzaXplJFYxPT0iY2hyMjAiXQoKIyBtYWtlIGEgc2xpZGluZyB3aW5kb3cgZGF0YXNldApwaF9zdyA8LSBzbGlkaW5nLndpbmRvdy50cmFuc2Zvcm0ocGgsIHdpZHRoID0gNTAwMDAsIGp1bXAgPSAxMDAwMCwgdHlwZSA9IDIpCiMgY3JhdGUgc2xpZGluZyB3aW5kb3cgaW5mbwp3aW5kb3dzPC1waF9zd0ByZWdpb24ubmFtZXMKd2luZG93czwtZ3N1YigiICIsIiIsIHdpbmRvd3MpCndpbmRvd3M8LWdzdWIoIjoiLCIiLHdpbmRvd3MpCndpbmRvd19zdGFydDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzFdKSkKd2luZG93X3N0b3A8LWFzLmludGVnZXIoc2FwcGx5KHdpbmRvd3MsIGZ1bmN0aW9uKHgpIHVubGlzdChzdHJzcGxpdCh4LCAiLSIpKVsyXSkpCndpbmRvdzwtZGF0YS5mcmFtZShzdGFydCA9IHdpbmRvd19zdGFydCwgc3RvcCA9IHdpbmRvd19zdG9wLCAKICAgICAgICAgICAgICAgICAgICAgIG1pZCA9IHdpbmRvd19zdGFydCArICh3aW5kb3dfc3RvcC13aW5kb3dfc3RhcnQpLzIpCgojY2FsY3VsYXRlIGRpdmVyc2l0eSBzdGF0cwpwaF9zdyA8LSBkaXZlcnNpdHkuc3RhdHMocGhfc3csIHBpID0gVFJVRSkKcGhfc3cgPC0gRl9TVC5zdGF0cyhwaF9zdywgbW9kZSA9ICJudWNsZW90aWRlIikKIyBleHRyYWN0IG51Y2xlb3RpZGUgZGl2ZXJzaXR5IGFuZCBjb3JyZWN0IGZvciB3aW5kb3cgc2l6ZQpuZCA8LSBwaF9zd0BudWMuZGl2ZXJzaXR5LndpdGhpbi81MDAwMAojIG1ha2UgZ3JvdXAgbmFtZSB2ZWN0b3IgYW5kIHJlbmFtZSB0aGUgY29sdW1ucwpncm91cG5hbWVzIDwtIHNvcnQodW5pcXVlKHBvcHMkZ3JvdXApKQpjb2xuYW1lcyhuZCkgPC0gcGFzdGUwKGdyb3VwbmFtZXMsICJfcGkiKQojIGV4dHJhY3QgZnN0IHZhbHVlcwpmc3QgPC0gdChwaF9zd0BudWMuRl9TVC5wYWlyd2lzZSkKIyBleHRyYWN0IGR4eSAtIHBhaXJ3aXNlIGFic29sdXRlIG51Y2xlb3RpZGUgZGl2ZXJzaXR5CmR4eSA8LSBnZXQuZGl2ZXJzaXR5KHBoX3N3LCBiZXR3ZWVuID0gVClbWzJdXS81MDAwMAojIHNldCB0aGUgY29sdW1uIG5hbWVzIAp4IDwtIGNvbG5hbWVzKGZzdCkKeCA8LSBzdWIoInBvcDEiLCBncm91cG5hbWVzWzFdLCB4KQp4IDwtIHN1YigicG9wMiIsIGdyb3VwbmFtZXNbMl0sIHgpCnggPC0gc3ViKCJwb3AzIiwgZ3JvdXBuYW1lc1szXSwgeCkKeCA8LSBzdWIoIi8iLCAiXyIsIHgpCgpjb2xuYW1lcyhmc3QpPC1wYXN0ZTAoImZzdF8iLHgpCmNvbG5hbWVzKGR4eSk8LXBhc3RlMCgiZHh5XyIseCkKCiNjb21iaW5lIGFsbCBkYXRhCnBoX2RhdGEgPC0gYXNfdGliYmxlKGRhdGEuZnJhbWUod2luZG93LCBuZCwgZnN0LCBkeHkpKQp3cml0ZS5jc3YocGhfZGF0YSwiLi4vT3V0cHV0L1BDQS9QSF9ub1RCX2NocjIwX3BvcGdlbm9tZV9zdGF0cy5jc3YiKQoKY29tYjwtY29tYm4oZ3JvdXBuYW1lcywgMikKY29tYjwtdChjb21iKQpmb3IgKGkgaW4gMTpucm93KGNvbWIpKXsKICAgICAgICBwb3AxPC1jb21iW2ksMV0KICAgICAgICBwb3AyPC1jb21iW2ksMl0KICAgICAgICBkdDwtcGhfZGF0YVssIGMoIm1pZCIsIHBhc3RlMCgiZnN0XyIsIHBvcDEsIl8iLHBvcDIpLHBhc3RlMCgiZHh5XyIscG9wMSwiXyIscG9wMiksIHBhc3RlMChwb3AxLCJfcGkiKSxwYXN0ZTAocG9wMiwiX3BpIikpIF0KICAgICAgICBjb2xuYW1lcyhkdClbMjozXTwtYygiRnN0IiwiRHh5IikKICAgIAogICAgICAgIGR0X2c8LWdhdGhlcihkdCwgLW1pZCwga2V5ID0gInN0YXQiLCB2YWx1ZSA9ICJ2YWx1ZSIpCiAgICAgICAgZHRfZyRzdGF0PC1mYWN0b3IoZHRfZyRzdGF0LCBsZXZlbHM9YygiRnN0IiwiRHh5Iixjb2xuYW1lcyhkdClbNF0sIGNvbG5hbWVzKGR0KVs1XSkpCiAgICAgICAgZ2dwbG90KGR0X2csIGFlcyhtaWQvMTBeNiwgdmFsdWUsIGNvbG91ciA9IHN0YXQpKSArIGdlb21fbGluZSgpKwogICAgICAgICAgICBmYWNldF9ncmlkKHN0YXR+Liwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgICAgICAgICB4bGFiKCJQb3NpdGlvbiAoTWIpIikreWxhYignJykrCiAgICAgICAgICAgIHRoZW1lX2xpZ2h0KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpK2dndGl0bGUocGFzdGUwKCJDaHIyMCAiLHBvcDEsIiB2cy4iLCBwb3AyKSkrCiAgICAgICAgICAgIHNjYWxlX3hfY29udGludW91cyhtaW5vcl9icmVha3MgPSBzZXEoMSwgY2hyLDEgKSkKICAgICAgICBnZ3NhdmUocGFzdGUwKCIuLi9PdXRwdXQvUENBL0NoMjBfRGl2ZXJzaXR5X3N0YXRzXyIscG9wMSwiLnZzLiIsIHBvcDIsIi5wbmciKSwgd2lkdGggPSA5LCBoZWlnaHQgPSA0LCBkcGk9MTUwKQogICAgfQpgYGAKIVtdKC4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfR3JvdXAxLnZzLkdyb3VwMi5wbmcpe3dpZHRoPTcwJX0KIVtdKC4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfR3JvdXAxLnZzLkdyb3VwMy5wbmcpe3dpZHRoPTcwJX0KIVtdKC4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfR3JvdXAyLnZzLkdyb3VwMy5wbmcpe3dpZHRoPTcwJX0KCgojIyMgSG93IHRoZSBncm91cGluZyBvdmVybGFwIGJldHdlZW4gJ2FsbC1wb3AnIHZzLiAnUFdTb25seSc/CmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiMgYzIwPSBQV1Nvbmx5IGNocjIwICthbGxwb3BzCgpjaHIyMCRTYW1wbGVbY2hyMjAkR3JvdXA9PSJHcm91cDMiJmNocjIwJHBvcD09IlBXUyJdICMxIHNhbXBsZSAoJzA1OTBfUFdTOTEnKQpnMl9hPC1jaHIyMCRTYW1wbGVbY2hyMjAkR3JvdXA9PSJHcm91cDIiJmNocjIwJHBvcD09IlBXUyJdICMyNSBzYW1wbGVzCiNbMV0gIjAzNjdfUFdTMDciICIwNDEyX1BXUzA3IiAiMDU2MF9QV1MwNyIgIjExNDZfUFdTMDciICIxMTQ4X1BXUzA3IiAiMTE1MF9QV1MwNyIgIjA0NzVfUFdTMTciICIwNjUyX1BXUzE3IgojWzldICIwOTU2X1BXUzE3IiAiMDk1OF9QV1MxNyIgIjA5NzhfUFdTMTciICIwOTg0X1BXUzE3IiAiMTAzNF9QV1MxNyIgIjEwMzZfUFdTMTciICIxMDM3X1BXUzE3IiAiMDU2NF9QV1M5MSIKI1sxN10gIjA2NzFfUFdTOTEiICIwNzAwX1BXUzkxIiAiMTIwM19QV1M5MSIgIjEyMDdfUFdTOTEiICIwNzU1X1BXUzk2IiAiMDc1N19QV1M5NiIgIjA5NjFfUFdTOTYiICIxMDc5X1BXUzk2IgojWzI1XSAiMTExNl9QV1M5NiIKZzNfcDwtYzIwJFNhbXBsZVtjMjAkZ3JvdXA9PSJHcm91cDMiXSAjMjMgaW5kaXZpZHVhbHMKZzJfcDwtYzIwJFNhbXBsZVtjMjAkZ3JvdXA9PSJHcm91cDIiXSAjMTEwIHNhbXBsZXMKCiNEbyBwd3MtZ3JvdXAzIHNhbXBsZXMgYmVsb25nIHRvIGFsbC1ncm91cDM/CiMKZzNfcFtnM19wICVpbiUgZzJfYV0gI29ubHkgMyBzYW1wbGVzIGZyb20gR3JvdXAzX1BXUyBiZWxvZ24gdG8gZ3JvdXAyLUFsbAojIjA5NTZfUFdTMTciICIwNjUyX1BXUzE3IiAiMDcwMF9QV1M5MSIKZzJfcFtnMl9wICVpbiUgZzJfYV0gIzE0IHNhbXBsZXMgZnJvbSBHcm91cDJfUFdTIGJlbG9uZyB0byBHcm91cDJfQWxsCiNbMV0gIjAzNjdfUFdTMDciICIwNTYwX1BXUzA3IiAiMTE0Nl9QV1MwNyIgIjExNDhfUFdTMDciICIwNDc1X1BXUzE3IiAiMDk1OF9QV1MxNyIgIjA5ODRfUFdTMTciICIxMDM2X1BXUzE3IgojWzldICIxMDM3X1BXUzE3IiAiMDU2NF9QV1M5MSIgIjA2NzFfUFdTOTEiICIwNzU1X1BXUzk2IiAiMDk2MV9QV1M5NiIgIjExMTZfUFdTOTYiCgoKI2RpZmZlcmVudCBncm91cGluZyAodmVydGljYWwoUEMyKSB2cy4gaG9yaXpvbnRhbCAoUEMxKSBjbHVzdGVyaW5nKQojQ3JlYXRlIG5ldyBncm91cHMgc2VwYXJhdGVkIGFsb25nIFBDMiAtPmNhbGwgJ2NsdXN0ZXJzJwoKcGNhMjA8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL25vVEJfcGNhX2NocjIwLmNzdiIpCmMzLjE8LXBjYTIwW3BjYTIwJFBDMj4wLjA2JnBjYTIwJFBDMTwwLjA1LF0gIzQ2CmMzLjI8LXBjYTIwW3BjYTIwJFBDMj4wLjAxJnBjYTIwJFBDMT4wLjA1MDksXSAjMjMKYzMuMzwtcGNhMjBbcGNhMjAkUEMyPigtMC4wMykmcGNhMjAkUEMxPjAuMTIsXSAjMTkgQ0EgaW52ZXJzaW9uCgpjMi4xPC1wY2EyMFtwY2EyMCRQQzI+KC0wLjAxMSkmcGNhMjAkUEMyPDAuMDYmcGNhMjAkUEMxPigtMC4wMikmcGNhMjAkUEMxPDAuMDEsXSAjMjE2CmMyLjI8LXBjYTIwW3BjYTIwJFBDMj4oLTAuMDUpJnBjYTIwJFBDMjwwLjAzNSZwY2EyMCRQQzE+KDAuMDE1KSZwY2EyMCRQQzE8MC4wNzksXSAjMzcKYzIuMzwtcGNhMjBbcGNhMjAkUEMyPigtMC4xKSZwY2EyMCRQQzI8KC0wLjA3KSZwY2EyMCRQQzE+KDAuMSksXSAjMTIKCmMxLjE8LXBjYTIwW3BjYTIwJFBDMjwoLTAuMDExKSZwY2EyMCRQQzE8MC4wLF0gIzI0MQpjMS4yPC1wY2EyMFtwY2EyMCRQQzI8KC0wLjA1KSZwY2EyMCRQQzI8MC4wMzUmcGNhMjAkUEMxPjAmcGNhMjAkUEMxPDAuMDUsXSAjMjYKYzEuMzwtcGNhMjBbcGNhMjAkUEMyPCgtMC4xKSZwY2EyMCRQQzE+KDAuMSksXSAjMQoKcGNhMjAkQ2x1c3RlcjwtMQpwY2EyMCRTdWJjbHVzdGVyPC0xLjEKcGNhMjAkU3ViY2x1c3RlcltwY2EyMCRTYW1wbGUgJWluJSBjMS4yJFNhbXBsZV08LTEuMgpwY2EyMCRTdWJjbHVzdGVyW3BjYTIwJFNhbXBsZSAlaW4lIGMxLjMkU2FtcGxlXTwtMS4zCgpwY2EyMCRDbHVzdGVyW3BjYTIwJFNhbXBsZSAlaW4lIGMoYzIuMSRTYW1wbGUsYzIuMiRTYW1wbGUsYzIuMyRTYW1wbGUpXTwtMgpwY2EyMCRTdWJjbHVzdGVyW3BjYTIwJFNhbXBsZSAlaW4lIGMyLjEkU2FtcGxlXTwtMi4xCnBjYTIwJFN1YmNsdXN0ZXJbcGNhMjAkU2FtcGxlICVpbiUgYzIuMiRTYW1wbGVdPC0yLjIKcGNhMjAkU3ViY2x1c3RlcltwY2EyMCRTYW1wbGUgJWluJSBjMi4zJFNhbXBsZV08LTIuMwoKcGNhMjAkQ2x1c3RlcltwY2EyMCRTYW1wbGUgJWluJSBjKGMzLjEkU2FtcGxlLGMzLjIkU2FtcGxlLGMzLjMkU2FtcGxlKV08LTMKcGNhMjAkU3ViY2x1c3RlcltwY2EyMCRTYW1wbGUgJWluJSBjMy4xJFNhbXBsZV08LTMuMQpwY2EyMCRTdWJjbHVzdGVyW3BjYTIwJFNhbXBsZSAlaW4lIGMzLjIkU2FtcGxlXTwtMy4yCnBjYTIwJFN1YmNsdXN0ZXJbcGNhMjAkU2FtcGxlICVpbiUgYzMuMyRTYW1wbGVdPC0zLjMKCiNwY2EyMCRHcm91cGluZzwtMQojcGNhMjAkR3JvdXBbcGNhMjAkU2FtcGxlICVpbiUgYyhjMS4yJFNhbXBsZSxjMi4yJFNhbXBsZSxjMy4yJFNhbXBsZSldPC0yCiNwY2EyMCRHcm91cFtwY2EyMCRTYW1wbGUgJWluJSBjKGMxLjMkU2FtcGxlLGMyLjMkU2FtcGxlLGMzLjMkU2FtcGxlKV08LTIKCnBjYTIwPC1tZXJnZShwY2EyMCwgY2hyMjBbLGMoIlNhbXBsZSIsIkdyb3VwIiwieXIucG9wIildLCBieT0iU2FtcGxlIikKd3JpdGUuY3N2KHBjYTIwLCIuLi9PdXRwdXQvUENBL2NocjIwX2dyb3VwX2NsdXN0ZXIuY3N2Iiwgcm93Lm5hbWVzPUYpCgojY3JlYXRlIGNvbG9ycyBiYXNlZCBvbiBjbHVzdGVyCmNjb2xzPC1jKCIjZmQ4ZDNjIiwiI2ZkYmU4NSIsIiNmZGQ0OWUiLCIjMzE4MmJkIiwiIzZiYWVkNiIsIiM5ZWNhZTEiLCIjZGY2NWIwIiwiI2M5OTRjNyIsIiNkNGI5ZGEiKQoKCmdncGxvdCgpKwogICAgICAgIGdlb21fcG9pbnQoZGF0YSA9IHBjYTIwLCBhZXMoeCA9IFBDMSwgeSA9IFBDMiwgY29sb3IgPSBmYWN0b3IoU3ViY2x1c3RlciksIGZpbGwgPSBmYWN0b3IoU3ViY2x1c3RlciksIHNoYXBlID0gZmFjdG9yKHllYXIpKSwgc2l6ZSA9IDMpKwogICAgICAgIHNjYWxlX3NoYXBlX21hbnVhbCh2YWx1ZXM9YygyMywyNSwzLDMsMjEpLCBuYW1lPSJZZWFyIikrCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMChjY29scywiNjYiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWNjb2xzLCBuYW1lPSJQb3B1bGF0aW9uIikrCiAgICAgICAgdGhlbWVfYncoKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgIHN0YXRfZWxsaXBzZShkYXRhPXBjYTIwLCBhZXMoeD1QQzEsIHk9UEMyLCBncm91cD1mYWN0b3IoU3ViY2x1c3RlcikpLCBjb2xvcj0iZ3JheTUwIiwgc2l6ZT0wLjIsbGV2ZWw9MC45OTkpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9DaHIyMF9DbHVzdGVyLnN1YmNsdXN0ZXIucG5nIiwgd2lkdGggPSA2LCBoZWlnaHQgPSA0LjUsIGRwaT0zMDApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9DaHIyMF9DbHVzdGVyLnN1YmNsdXN0ZXIucG5nKXt3aWR0aD02MCV9CgojIyMgTG9vayBhdCBGc3QgYmV0d2VlbiBDbHVzdGVycyAoc2VwYXJ0ZWQgYnkgUEMyKSB3aXRoaW4gY2hyMjAgZm9yIGFsbCBwb3BzCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPVRSVUUsIHdhcm5pbmc9RkFMU0V9CnBoIDwtIHJlYWREYXRhKCIuLi9EYXRhL25ld192Y2YvY2gyMC8iLCBmb3JtYXQgPSAiVkNGIiwgaW5jbHVkZS51bmtub3duID0gVFJVRSwgRkFTVCA9IFRSVUUpCnBvcF9pbmZvPC1yZWFkLmNzdigiLi4vRGF0YS9TYW1wbGVfbWV0YWRhdGFfODkycG9wcy5jc3YiKQpwb3BzPC1wb3BfaW5mb1twb3BfaW5mbyRwb3AhPSJUQiIsXQoKI2Fzc2lnbiBncm91cHMKcG9wcyRncm91cDwtIkNsdXN0ZXIxIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgcGNhMjAkU2FtcGxlW3BjYTIwJENsdXN0ZXI9PTJdXSA8LSJDbHVzdGVyMiIKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIHBjYTIwJFNhbXBsZVtwY2EyMCRDbHVzdGVyPT0zXV0gPC0iQ2x1c3RlcjMiCnBvcHVsYXRpb25zIDwtIHNwbGl0KHBvcHMkU2FtcGxlLCBwb3BzJGdyb3VwKQpwaDwtc2V0LnBvcHVsYXRpb25zKHBoLCBwb3B1bGF0aW9ucywgZGlwbG9pZCA9IFQpCgojIHNldCB0aGUgY2hyb21vc29tZSBzaXplCmNocnNpemU8LXJlYWQudGFibGUoIi4uL0RhdGEvbmV3X3ZjZi9jaHJfc2l6ZXMuYmVkIikKY2hyPC1jaHJzaXplJFYzW2NocnNpemUkVjE9PSJjaHIyMCJdCgojIG1ha2UgYSBzbGlkaW5nIHdpbmRvdyBkYXRhc2V0CnBoX3N3IDwtIHNsaWRpbmcud2luZG93LnRyYW5zZm9ybShwaCwgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKIyBjcmF0ZSBzbGlkaW5nIHdpbmRvdyBpbmZvCndpbmRvd3M8LXBoX3N3QHJlZ2lvbi5uYW1lcwp3aW5kb3dzPC1nc3ViKCIgIiwiIiwgd2luZG93cykKd2luZG93czwtZ3N1YigiOiIsIiIsd2luZG93cykKd2luZG93X3N0YXJ0PC1hcy5pbnRlZ2VyKHNhcHBseSh3aW5kb3dzLCBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi0iKSlbMV0pKQp3aW5kb3dfc3RvcDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzJdKSkKd2luZG93PC1kYXRhLmZyYW1lKHN0YXJ0ID0gd2luZG93X3N0YXJ0LCBzdG9wID0gd2luZG93X3N0b3AsIAogICAgICAgICAgICAgICAgICAgICAgbWlkID0gd2luZG93X3N0YXJ0ICsgKHdpbmRvd19zdG9wLXdpbmRvd19zdGFydCkvMikKCiNjYWxjdWxhdGUgZGl2ZXJzaXR5IHN0YXRzCnBoX3N3IDwtIGRpdmVyc2l0eS5zdGF0cyhwaF9zdywgcGkgPSBUUlVFKQpwaF9zdyA8LSBGX1NULnN0YXRzKHBoX3N3LCBtb2RlID0gIm51Y2xlb3RpZGUiKQojIGV4dHJhY3QgbnVjbGVvdGlkZSBkaXZlcnNpdHkgYW5kIGNvcnJlY3QgZm9yIHdpbmRvdyBzaXplCm5kIDwtIHBoX3N3QG51Yy5kaXZlcnNpdHkud2l0aGluLzUwMDAwCiMgbWFrZSBncm91cCBuYW1lIHZlY3RvciBhbmQgcmVuYW1lIHRoZSBjb2x1bW5zCmdyb3VwbmFtZXMgPC0gc29ydCh1bmlxdWUocG9wcyRncm91cCkpCmNvbG5hbWVzKG5kKSA8LSBwYXN0ZTAoZ3JvdXBuYW1lcywgIl9waSIpCiMgZXh0cmFjdCBmc3QgdmFsdWVzCmZzdCA8LSB0KHBoX3N3QG51Yy5GX1NULnBhaXJ3aXNlKQojIGV4dHJhY3QgZHh5IC0gcGFpcndpc2UgYWJzb2x1dGUgbnVjbGVvdGlkZSBkaXZlcnNpdHkKZHh5IDwtIGdldC5kaXZlcnNpdHkocGhfc3csIGJldHdlZW4gPSBUKVtbMl1dLzUwMDAwCiMgc2V0IHRoZSBjb2x1bW4gbmFtZXMgCnggPC0gY29sbmFtZXMoZnN0KQp4IDwtIHN1YigicG9wMSIsIGdyb3VwbmFtZXNbMV0sIHgpCnggPC0gc3ViKCJwb3AyIiwgZ3JvdXBuYW1lc1syXSwgeCkKeCA8LSBzdWIoInBvcDMiLCBncm91cG5hbWVzWzNdLCB4KQp4IDwtIHN1YigiLyIsICJfIiwgeCkKCmNvbG5hbWVzKGZzdCk8LXBhc3RlMCgiZnN0XyIseCkKY29sbmFtZXMoZHh5KTwtcGFzdGUwKCJkeHlfIix4KQoKI2NvbWJpbmUgYWxsIGRhdGEKcGhfZGF0YSA8LSBhc190aWJibGUoZGF0YS5mcmFtZSh3aW5kb3csIG5kLCBmc3QsIGR4eSkpCndyaXRlLmNzdihwaF9kYXRhLCIuLi9PdXRwdXQvUENBL1BIX25vVEJfY2hyMjBfQ2x1c3RlcnNfcG9wZ2Vub21lX3N0YXRzLmNzdiIpCgpjb21iPC1jb21ibihncm91cG5hbWVzLCAyKQpjb21iPC10KGNvbWIpCmZvciAoaSBpbiAxOm5yb3coY29tYikpewogICAgICAgIHBvcDE8LWNvbWJbaSwxXQogICAgICAgIHBvcDI8LWNvbWJbaSwyXQogICAgICAgIGR0PC1waF9kYXRhWywgYygibWlkIiwgcGFzdGUwKCJmc3RfIiwgcG9wMSwiXyIscG9wMikscGFzdGUwKCJkeHlfIixwb3AxLCJfIixwb3AyKSwgcGFzdGUwKHBvcDEsIl9waSIpLHBhc3RlMChwb3AyLCJfcGkiKSkgXQogICAgICAgIGNvbG5hbWVzKGR0KVsyOjNdPC1jKCJGc3QiLCJEeHkiKQogICAgCiAgICAgICAgZHRfZzwtZ2F0aGVyKGR0LCAtbWlkLCBrZXkgPSAic3RhdCIsIHZhbHVlID0gInZhbHVlIikKICAgICAgICBkdF9nJHN0YXQ8LWZhY3RvcihkdF9nJHN0YXQsIGxldmVscz1jKCJGc3QiLCJEeHkiLGNvbG5hbWVzKGR0KVs0XSwgY29sbmFtZXMoZHQpWzVdKSkKICAgICAgICBnZ3Bsb3QoZHRfZywgYWVzKG1pZC8xMF42LCB2YWx1ZSwgY29sb3VyID0gc3RhdCkpICsgZ2VvbV9saW5lKCkrCiAgICAgICAgICAgIGZhY2V0X2dyaWQoc3RhdH4uLCBzY2FsZXMgPSAiZnJlZV95IikrCiAgICAgICAgICAgIHhsYWIoIlBvc2l0aW9uIChNYikiKSt5bGFiKCcnKSsKICAgICAgICAgICAgdGhlbWVfbGlnaHQoKSArIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9ICJub25lIikrZ2d0aXRsZShwYXN0ZTAoIkNocjIwICIscG9wMSwiIHZzLiIsIHBvcDIpKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IHNlcSgxLCBjaHIsMSApKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfIixwb3AxLCIudnMuIiwgcG9wMiwiLnBuZyIpLCB3aWR0aCA9IDksIGhlaWdodCA9IDQsIGRwaT0xNTApCn0KYGBgCiFbXSguLi9PdXRwdXQvUENBL0NoMjBfRGl2ZXJzaXR5X3N0YXRzX0NsdXN0ZXIxLnZzLkNsdXN0ZXIyLnBuZyl7d2lkdGg9NzAlfQoKIVtdKC4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfQ2x1c3RlcjEudnMuQ2x1c3RlcjMucG5nKXt3aWR0aD03MCV9CgoKIVtdKC4uL091dHB1dC9QQ0EvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfQ2x1c3RlcjIudnMuQ2x1c3RlcjMucG5nKXt3aWR0aD03MCV9CgojIyMgQ2hlY2sgUFdTb25seSBncm91cHMgbWF0Y2hlcyBjbHVzdGVyIG51Ym1lcnMgIApgYGB7cn0KcHdzMjA8LXBjYTIwW3BjYTIwJHBvcD09IlBXUyIsXQpwd3MyMDwtbWVyZ2UocHdzMjBbLGMoMTo1LDEyOjEzLDE1KV0sIGMyMFssYygiU2FtcGxlIiwiZ3JvdXAiKV0sIGJ5PSJTYW1wbGUiKQpwd3MyMCRHcm91cDwtYXMuaW50ZWdlcihnc3ViKCJHcm91cCIsICcnLHB3czIwJGdyb3VwKSkKcHdzMjAkbWF0Y2g8LWlmZWxzZShwd3MyMCRDbHVzdGVyPT1wd3MyMCRHcm91cCwgMCwgMSkKcHdzMjBbcHdzMjAkbWF0Y2g9PTEsXQoKCmBgYAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQpwaCA8LSByZWFkRGF0YSgiLi4vRGF0YS9uZXdfdmNmL2NoMjAvIiwgZm9ybWF0ID0gIlZDRiIsIGluY2x1ZGUudW5rbm93biA9IFRSVUUsIEZBU1QgPSBUUlVFKQpwb3BfaW5mbzwtcmVhZC5jc3YoIi4uL0RhdGEvU2FtcGxlX21ldGFkYXRhXzg5MnBvcHMuY3N2IikKcG9wczwtcG9wX2luZm9bcG9wX2luZm8kcG9wIT0iVEIiLF0KI2Fzc2lnbiBncm91cHMKcG9wcyRncm91cDwtIkNsdXN0ZXIxLjEiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBwY2EyMCRTYW1wbGVbcGNhMjAkU3ViY2x1c3Rlcj09MS4yXV0gPC0iQ2x1c3RlcjEuMiIKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIHBjYTIwJFNhbXBsZVtwY2EyMCRTdWJjbHVzdGVyPT0xLjNdXSA8LSJDbHVzdGVyMi4zIiNncm91cCB3aXRoIGNsdXN0ZXIyLjMgc2luY2UgMSBzYW1wbGUKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIHBjYTIwJFNhbXBsZVtwY2EyMCRTdWJjbHVzdGVyPT0yLjFdXSA8LSJDbHVzdGVyMi4xIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgcGNhMjAkU2FtcGxlW3BjYTIwJFN1YmNsdXN0ZXI9PTIuMl1dIDwtIkNsdXN0ZXIyLjIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBwY2EyMCRTYW1wbGVbcGNhMjAkU3ViY2x1c3Rlcj09Mi4zXV0gPC0iQ2x1c3RlcjIuMyIKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIHBjYTIwJFNhbXBsZVtwY2EyMCRTdWJjbHVzdGVyPT0zLjFdXSA8LSJDbHVzdGVyMy4xIgpwb3BzJGdyb3VwW3BvcHMkU2FtcGxlICVpbiUgcGNhMjAkU2FtcGxlW3BjYTIwJFN1YmNsdXN0ZXI9PTMuMl1dIDwtIkNsdXN0ZXIzLjIiCnBvcHMkZ3JvdXBbcG9wcyRTYW1wbGUgJWluJSBwY2EyMCRTYW1wbGVbcGNhMjAkU3ViY2x1c3Rlcj09My4zXV0gPC0iQ2x1c3RlcjMuMyIKCnBvcHVsYXRpb25zIDwtIHNwbGl0KHBvcHMkU2FtcGxlLCBwb3BzJGdyb3VwKQpwaDwtc2V0LnBvcHVsYXRpb25zKHBoLCBwb3B1bGF0aW9ucywgZGlwbG9pZCA9IFQpCgojIHNldCB0aGUgY2hyb21vc29tZSBzaXplCmNocnNpemU8LXJlYWQudGFibGUoIi4uL0RhdGEvbmV3X3ZjZi9jaHJfc2l6ZXMuYmVkIikKY2hyPC1jaHJzaXplJFYzW2NocnNpemUkVjE9PSJjaHIyMCJdCgojIG1ha2UgYSBzbGlkaW5nIHdpbmRvdyBkYXRhc2V0CnBoX3N3IDwtIHNsaWRpbmcud2luZG93LnRyYW5zZm9ybShwaCwgd2lkdGggPSA1MDAwMCwganVtcCA9IDEwMDAwLCB0eXBlID0gMikKIyBjcmF0ZSBzbGlkaW5nIHdpbmRvdyBpbmZvCndpbmRvd3M8LXBoX3N3QHJlZ2lvbi5uYW1lcwp3aW5kb3dzPC1nc3ViKCIgIiwiIiwgd2luZG93cykKd2luZG93czwtZ3N1YigiOiIsIiIsd2luZG93cykKd2luZG93X3N0YXJ0PC1hcy5pbnRlZ2VyKHNhcHBseSh3aW5kb3dzLCBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi0iKSlbMV0pKQp3aW5kb3dfc3RvcDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzJdKSkKd2luZG93PC1kYXRhLmZyYW1lKHN0YXJ0ID0gd2luZG93X3N0YXJ0LCBzdG9wID0gd2luZG93X3N0b3AsIAogICAgICAgICAgICAgICAgICAgICAgbWlkID0gd2luZG93X3N0YXJ0ICsgKHdpbmRvd19zdG9wLXdpbmRvd19zdGFydCkvMikKCiNjYWxjdWxhdGUgZGl2ZXJzaXR5IHN0YXRzCnBoX3N3IDwtIGRpdmVyc2l0eS5zdGF0cyhwaF9zdywgcGkgPSBUUlVFKQpwaF9zdyA8LSBGX1NULnN0YXRzKHBoX3N3LCBtb2RlID0gIm51Y2xlb3RpZGUiKQpncm91cG5hbWVzIDwtIHNvcnQodW5pcXVlKHBvcHMkZ3JvdXApKQpmc3QgPC0gdChwaF9zd0BudWMuRl9TVC5wYWlyd2lzZSkKZHh5IDwtIGdldC5kaXZlcnNpdHkocGhfc3csIGJldHdlZW4gPSBUKVtbMl1dLzUwMDAwCiMgc2V0IHRoZSBjb2x1bW4gbmFtZXMgCnggPC0gY29sbmFtZXMoZnN0KQpmb3IgKGkgaW4gMTpsZW5ndGgoeCkpewogICAgeCA8LSBzdWIocGFzdGUwKCJwb3AiLGkpLCBncm91cG5hbWVzW2ldLCB4KQp9CnggPC0gc3ViKCIvIiwgIl8iLCB4KQoKY29sbmFtZXMoZnN0KTwtcGFzdGUwKCJmc3RfIix4KQpjb2xuYW1lcyhkeHkpPC1wYXN0ZTAoImR4eV8iLHgpCgojY29tYmluZSBhbGwgZGF0YQpwaF9kYXRhMiA8LSBhc190aWJibGUoZGF0YS5mcmFtZSh3aW5kb3csIG5kLCBmc3QsIGR4eSkpCndyaXRlLmNzdihwaF9kYXRhMiwiLi4vT3V0cHV0L1BDQS9QSF9ub1RCX2NocjIwX1N1YmNsdXN0ZXJzX3BvcGdlbm9tZV9zdGF0cy5jc3YiKQoKY29tYjwtY29tYm4oZ3JvdXBuYW1lcywgMikKY29tYjwtdChjb21iKQpmb3IgKGkgaW4gMTpucm93KGNvbWIpKXsKICAgICAgICBwb3AxPC1jb21iW2ksMV0KICAgICAgICBwb3AyPC1jb21iW2ksMl0KICAgICAgICBkdDwtcGhfZGF0YTJbLCBjKCJtaWQiLCBwYXN0ZTAoImZzdF8iLCBwb3AxLCJfIixwb3AyKSxwYXN0ZTAoImR4eV8iLHBvcDEsIl8iLHBvcDIpKSBdCiAgICAgICAgY29sbmFtZXMoZHQpWzI6M108LWMoIkZzdCIsIkR4eSIpCiAgICAKICAgICAgICBkdF9nPC1nYXRoZXIoZHQsIC1taWQsIGtleSA9ICJzdGF0IiwgdmFsdWUgPSAidmFsdWUiKQogICAgICAgIGR0X2ckc3RhdDwtZmFjdG9yKGR0X2ckc3RhdCwgbGV2ZWxzPWMoIkZzdCIsIkR4eSIsY29sbmFtZXMoZHQpWzRdLCBjb2xuYW1lcyhkdClbNV0pKQogICAgICAgIGdncGxvdChkdF9nLCBhZXMobWlkLzEwXjYsIHZhbHVlLCBjb2xvdXIgPSBzdGF0KSkgKyBnZW9tX2xpbmUoKSsKICAgICAgICAgICAgZmFjZXRfZ3JpZChzdGF0fi4sIHNjYWxlcyA9ICJmcmVlX3kiKSsKICAgICAgICAgICAgeGxhYigiUG9zaXRpb24gKE1iKSIpK3lsYWIoJycpKwogICAgICAgICAgICB0aGVtZV9saWdodCgpICsgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gIm5vbmUiKStnZ3RpdGxlKHBhc3RlMCgiQ2hyMjAgIixwb3AxLCIgdnMuIiwgcG9wMikpKwogICAgICAgICAgICBzY2FsZV94X2NvbnRpbnVvdXMobWlub3JfYnJlYWtzID0gc2VxKDEsIGNociwxICkpCiAgICAgICAgZ2dzYXZlKHBhc3RlMCgiLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c18iLHBvcDEsIi52cy4iLCBwb3AyLCIucG5nIiksIHdpZHRoID0gOCwgaGVpZ2h0ID0gMiwgZHBpPTE1MCkKfQpgYGAKCiMjIyMgU3ViY2x1c3RlcnMgd2l0aGluIHRoZSBDbHVzdGVyIGFyZSBiYXNlZCBvbiB0aGUgaW52ZXJzaW9uCgohW10oLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c19DbHVzdGVyMS4xLnZzLkNsdXN0ZXIxLjIucG5nKXt3aWR0aD00MCV9ICAKIVtdKC4uL091dHB1dC9QQ0EvY2hyMjAvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfQ2x1c3RlcjIuMS52cy5DbHVzdGVyMi4yLnBuZyl7d2lkdGg9NDAlfQohW10oLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c19DbHVzdGVyMi4xLnZzLkNsdXN0ZXIyLjMucG5nKXt3aWR0aD00MCV9CgohW10oLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c19DbHVzdGVyMy4xLnZzLkNsdXN0ZXIzLjMucG5nKXt3aWR0aD00MCV9CiFbXSguLi9PdXRwdXQvUENBL2NocjIwL0NoMjBfRGl2ZXJzaXR5X3N0YXRzX0NsdXN0ZXIzLjIudnMuQ2x1c3RlcjMuMy5wbmcpe3dpZHRoPTQwJX0KCiMjIyMgYmV0d2VlbiBjbHVzdGVycyBhcmUgYmFzZWQgb24gdGhlIHJlZ2lvbiBhdCB0aGUgZW5kIG9mIGNocm9tc29tZQoKIVtdKC4uL091dHB1dC9QQ0EvY2hyMjAvQ2gyMF9EaXZlcnNpdHlfc3RhdHNfQ2x1c3RlcjEuMS52cy5DbHVzdGVyMy4xLnBuZyl7d2lkdGg9NDAlfQohW10oLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c19DbHVzdGVyMS4xLnZzLkNsdXN0ZXIyLjEucG5nKXt3aWR0aD00MCV9CgohW10oLi4vT3V0cHV0L1BDQS9jaHIyMC9DaDIwX0RpdmVyc2l0eV9zdGF0c19DbHVzdGVyMi4xLnZzLkNsdXN0ZXIyLjIucG5nKXt3aWR0aD00MCV9CiFbXSguLi9PdXRwdXQvUENBL2NocjIwL0NoMjBfRGl2ZXJzaXR5X3N0YXRzX0NsdXN0ZXIyLjMudnMuQ2x1c3RlcjMuMy5wbmcpe3dpZHRoPTQwJX0KCgo8YnI+CgojIyMgQ3JlYXRlIGEgc3RhY2tlZCBiYXItY2hhcnQgZm9yIGNsdXN0ZXJzCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQpwY2EyMDwtcmVhZC5jc3YoIi4uL091dHB1dC9QQ0EvY2hyMjBfZ3JvdXBfY2x1c3Rlci5jc3YiKQoKcGNhMjBfc3VtPC1kYXRhLmZyYW1lKHRhYmxlKHBjYTIwJFN1YmNsdXN0ZXIscGNhMjAkeXIucG9wKSkKY29sbmFtZXMocGNhMjBfc3VtKTwtYygiQ2x1c3RlciIsInlyLnBvcCIsIkZyZXEiKQpwY2EyMF9zdW0kaGVhZENsdXN0ZXI8LXN1YnN0cihwY2EyMF9zdW0kQ2x1c3RlciwgMSwxKQoKcGNhMjBfc3VtJHlyLnBvcDwtZmFjdG9yKHBjYTIwX3N1bSR5ci5wb3AsIGxldmVscz1jKCJQV1M5MSIsIlBXUzk2IiwiUFdTMDciLCJQV1MxNyIsIlNTOTYiLCJTUzA2IiwiU1MxNyIsIkJDMTciLCJXQTE3IiwiQ0ExNyIpKQoKIzEuIEdyb3Bpbmcgb25seSAobm90IHRoZSBpbnZlcnNpb24gY2x1c3RlcikKCmNocjIwX2NsPC1kYXRhLmZyYW1lKHRhYmxlKHBjYTIwJENsdXN0ZXIscGNhMjAkeXIucG9wKSkKY29sbmFtZXMoY2hyMjBfY2wpPC1jKCJDbHVzdGVyIiwieXIucG9wIiwiRnJlcSIpCmNocjIwX2NsJHlyLnBvcDwtZmFjdG9yKGNocjIwX2NsJHlyLnBvcCwgbGV2ZWxzPWMoIlBXUzkxIiwiUFdTOTYiLCJQV1MwNyIsIlBXUzE3IiwiU1M5NiIsIlNTMDYiLCJTUzE3IiwiQkMxNyIsIldBMTciLCJDQTE3IikpCmdncGxvdChjaHIyMF9jbCwgYWVzKHg9eXIucG9wLCB5PUZyZXEsIGZpbGw9Q2x1c3RlcikpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjgsIGNvbG9yPSJncmF5NDAiLHBvc2l0aW9uID0gImZpbGwiKSsKICAgIHRoZW1lX2xpbmVkcmF3KCkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSt5bGFiKCJQcm9wb3J0aW9uIG9mIGluZGl2aWR1YWxzIikrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2ZiYjRhZSIsIiNiM2NkZTMiLCIjY2NlYmM1IikpK3hsYWIoIiIpK2dndGl0bGUoIkNocjIwIEdyb3BpbmcgKG5vbi1pbnZlcnNpb24pIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL0NoMjBfcHJvcF9pbmRpdmlfaW4zZ3JvdXBzLm5vbkludmVyc2lvbi5wbmciLCB3aWR0aCA9IDcsIGhlaWdodCA9IDQsIGRwaT0zMDApCgoKI2NyZWF0ZSBjb2xvcnMgYmFzZWQgb24gY2x1c3RlcgpjY29sczwtYygiI2ZkOGQzYyIsIiNmZGJlODUiLCIjZmRkNDllIiwiIzMxODJiZCIsIiM2YmFlZDYiLCIjOWVjYWUxIiwiI2RmNjViMCIsIiNjOTk0YzciLCIjZDRiOWRhIikKCmdncGxvdChwY2EyMF9zdW0sIGFlcyh4PXlyLnBvcCwgeT1GcmVxLCBmaWxsPUNsdXN0ZXIpKSsKICAgIGdlb21fYmFyKHN0YXQ9ImlkZW50aXR5Iiwgd2lkdGg9MC44LCBjb2xvcj0iZ3JheTQwIixwb3NpdGlvbiA9ICJmaWxsIikrCiAgICB0aGVtZV9saW5lZHJhdygpK3RoZW1lKGxlZ2VuZC50aXRsZSA9IGVsZW1lbnRfYmxhbmsoKSkreWxhYigiUHJvcG9ydGlvbiBvZiBpbmRpdmlkdWFscyIpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPWNjb2xzKSt4bGFiKCIiKStnZ3RpdGxlKCJDaHIyMCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9DaDIwX3Byb3BfaW5kaXZpX2luQ2x1c3RlcnMucG5nIiwgd2lkdGggPSA3LCBoZWlnaHQgPSA0LCBkcGk9MzAwKQpgYGAKCiFbXSguLi9PdXRwdXQvUENBL0NoMjBfcHJvcF9pbmRpdmlfaW4zZ3JvdXBzLm5vbkludmVyc2lvbi5wbmcpe3dpZHRoPTYwJX0KCgohW10oLi4vT3V0cHV0L1BDQS9DaDIwX3Byb3BfaW5kaXZpX2luQ2x1c3RlcnMucG5nKXt3aWR0aD02MCV9CiFbXSguLi9PdXRwdXQvUENBL0NocjIwX0NsdXN0ZXIuc3ViY2x1c3Rlcl93aXRoTmFtZXMucG5nKXt3aWR0aD0zMCV9ICAgIAoKPGJyPgo8YnI+CgojIENocjQgICAKCiMjIFBDQSBjbHVzdGVycyBpbnRvIDMgZ3JvdXBzIGZvciBQV1Nvbmx5LCBidXQgbm90IHNvIGNsZWFyIHdoZW4gYWxsIHBvcHVsYXRpb25zIGFyZSBpbmNsZHVlZAohW10oLi4vT3V0cHV0L2Noci9jaDRfYWxsLnBuZyl7d2lkdGg9MzAlfSAhW10oLi4vT3V0cHV0L2Noci9jaDRfbm9UQi5wbmcpe3dpZHRoPTMwJX0KCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CgojcHJvcG9ydGlvbiBvZiB5ZWFyIGluIGVhY2ggZ3JvdXAKY2g0PC1yZWFkLmNzdigiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X3BjYV9jaHI0LmNzdiIpCmdwMS4xPC1jaDRbY2g0JFBDMT4wLjAyLF0KZ3AxLjI8LWNoNFtjaDQkUEMxPigtMC4wMikmY2g0JFBDMjwwLF0KZ3AxLjI8LWdwMS4yWyEoZ3AxLjIkU2FtcGxlJWluJSBncDEuMSRTYW1wbGUpLF0KZ3AxPC1yYmluZChncDEuMSwgZ3AxLjIpCgpncDMuMTwtY2g0W2NoNCRQQzE8KC0wLjA5KSZjaDQkUEMyPigtMC4wNiksXQpncDMuMjwtY2g0W2NoNCRQQzE8KC0wLjIpJmNoNCRQQzI8KC0wLjEpLF0KZ3AzPC1yYmluZChncDMuMSxncDMuMikKZ3AyPC1jaDRbIShjaDQkU2FtcGxlICVpbiUgYyhncDEkU2FtcGxlLCBncDMkU2FtcGxlKSksICBdCgp0YWJsZShncDEkeWVhcikgIzEyNwojMTk5MSAxOTk2IDIwMDcgMjAxNyAKIyAgMzIgICAzNyAgIDI5ICAgMjkgIAp0YWJsZShncDIkeWVhcikgIzg4CiMxOTkxIDE5OTYgMjAwNyAyMDE3IAojICAyMCAgIDI5ICAgMTQgICAyNSAgIAp0YWJsZShncDMkeWVhcikgIzE3CiMxOTkxIDE5OTYgMjAwNyAyMDE3IAojICAgNiAgICA2ICAgIDMgICAgMiAgCgpncDEkZ3JvdXA8LSJHcm91cDEiCmdwMiRncm91cDwtIkdyb3VwMiIKZ3AzJGdyb3VwPC0iR3JvdXAzIgpjNDwtcmJpbmQoZ3AxLGdwMixncDMpCndyaXRlLmNzdihjNCwgIi4uL091dHB1dC9QQ0EvUFdTb25seV93aXRoLmdyb3Vwc19wY2FfY2hyNC5jc3YiKQoKcGNvbHM8LWMoIiNkN2I1ZDgiLCIjZGY2NWIwIiwiI2RkMWM3NyIsIiM5ODAwNDMiKQpnZ3Bsb3QoKSsKICAgICAgICBnZW9tX3BvaW50KGRhdGEgPSBjNCwgYWVzKHggPSBQQzEsIHkgPSBQQzIsIGZpbGwgPSBmYWN0b3IoeWVhciksIGNvbG9yID0gZmFjdG9yKHllYXIpLCBzaGFwZSA9IGZhY3Rvcih5ZWFyKSksIHNpemUgPSAzKSsKICAgICAgICBzY2FsZV9zaGFwZV9tYW51YWwodmFsdWVzPWMoMjMsMjUsMywyMSksIGd1aWRlPSJub25lIikrCiAgICAgICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMChwY29scywiOTkiKSwgZ3VpZGU9Im5vbmUiKSsKICAgICAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPXBjb2xzWzE6NF0pKwogICAgICAgIHhsYWIocGFzdGUoIlBDIDEiKSkrCiAgICAgICAgeWxhYihwYXN0ZSgiUEMgMiIpKSsKICAgICAgICB0aGVtZV9idygpKwogICAgICAgIGdndGl0bGUoIkNocjQiKSsKICAgICAgICBndWlkZXMoc2hhcGUgPSBndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID1jKDIzLDI1LDMsMjEpKSwgZmlsbD1ndWlkZV9sZWdlbmQob3ZlcnJpZGUuYWVzID1wYXN0ZTAocGNvbHMsIjk5IikpKSt0aGVtZShsZWdlbmQudGl0bGUgPSBlbGVtZW50X2JsYW5rKCkpKwogICAgICAgIHN0YXRfZWxsaXBzZShkYXRhPWM0LCBhZXMoeD1QQzEsIHk9UEMyLCBncm91cD1ncm91cCksIGNvbG9yPSJncmF5NTAiLCBzaXplPTAuMixsZXZlbD0wLjk5NykrCiAgICAgICAgIGFubm90YXRlKCJ0ZXh0IiwgeD0wLjA1LCB5PS0wLjIsIGxhYmVsPSJHcm91cCAxIikrCiAgICBhbm5vdGF0ZSgidGV4dCIsIHg9LTAuMDgsIHk9LTAuMiwgbGFiZWw9Ikdyb3VwIDIiKSsKICAgIGFubm90YXRlKCJ0ZXh0IiwgeD0tMC4yMiwgeT0wLjIsIGxhYmVsPSJHcm91cCAzIikKZ2dzYXZlKCIuLi9PdXRwdXQvUENBL1BXU29ubHlfQ2g0X1BDQV93aXRoR3JvdXBzLnBuZyIsIHdpZHRoID0gNiwgaGVpZ2h0ID0gNC41LCBkcGk9MzAwKQojVEIgaXMgaW4gMSBncm91cCBmb3IgY2hyNApgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9DaDRfUENBX3dpdGhHcm91cHMucG5nKXt3aWR0aD03MCV9CgojIyMgQ3JlYXRlIGEgZ3JvdXBpbmcgc3VtbWFyeSBwbG90CgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGEgc3VtbWFyeQpjaDRfc3VtbWFyeTwtZGF0YS5mcmFtZSh5ZWFyPWMoMTk5MSwxOTk2LDIwMDcsMjAxNykpCmNoNF9zdW1tYXJ5JEdyb3VwMTwtYXMudmVjdG9yKHRhYmxlKGdwMSR5ZWFyKSkKY2g0X3N1bW1hcnkkR3JvdXAyPC1hcy52ZWN0b3IodGFibGUoZ3AyJHllYXIpKQpjaDRfc3VtbWFyeSRHcm91cDM8LWFzLnZlY3Rvcih0YWJsZShncDMkeWVhcikpCgojcXVpY2sgY2hpLXNxdWFyZSB0ZXN0IApjaGlzcS50ZXN0KGNoNF9zdW1tYXJ5WywyOjRdKQojWC1zcXVhcmVkID0gNC4zOTAyLCBkZiA9IDYsIHAtdmFsdWUgPSAwLjYyNAoKCmM0bTwtbWVsdChjaDRfc3VtbWFyeSwgaWQudmFycz0ieWVhciIpCmdncGxvdChjNG0sIGFlcyh4PWZhY3Rvcih5ZWFyKSwgeT12YWx1ZSwgZmlsbD12YXJpYWJsZSkpKwogICAgZ2VvbV9iYXIoc3RhdD0iaWRlbnRpdHkiLCB3aWR0aD0wLjUsIGNvbG9yPSJncmF5NDAiLHBvc2l0aW9uID0gImZpbGwiKSsKICAgIHRoZW1lX2xpbmVkcmF3KCkrdGhlbWUobGVnZW5kLnRpdGxlID0gZWxlbWVudF9ibGFuaygpKSt5bGFiKCJQcm9wb3J0aW9uIG9mIGluZGl2aWR1YWxzIikrCiAgICBzY2FsZV9maWxsX21hbnVhbCh2YWx1ZXM9YygiI2ZiYjRhZSIsIiNiM2NkZTMiLCIjY2NlYmM1IikpK3hsYWIoIlllYXIiKStnZ3RpdGxlKCJQV1MgQ2hyNCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1NfY2g0X3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0xNTApCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfY2g0X3Byb3BfaW5kaXZpX2luM2dyb3Vwcy5wbmcpe3dpZHRoPTcwJX0KCiMjIyBDYWxjdWFsdGUgRnN0IGJldHdlZW4gR3JvdXBzIHdpdGhpbiBjaHI0IChQV1Nvbmx5KQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1UUlVFLCB3YXJuaW5nPUZBTFNFfQojIHJlYWQgY2hyNCBmcm9tIHRoZSAnUFdTb25seScgZmlsZQojIFN1YnNldCBWQ0YgYnkgY2hyMjAgCiNiY2Z0b29scyB2aWV3ICAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfTlMwLjVfbWFmMDUudmNmLmd6IC0tcmVnaW9ucyBjaHIyMCA+IC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9jaDIwX21hZjA1LnZjZgoKCnB3cyA8LSByZWFkRGF0YSgiLi4vRGF0YS9uZXdfdmNmL1BXU29ubHkvUFdTb25seV9jaHI0LyIsIGZvcm1hdCA9ICJWQ0YiLCBpbmNsdWRlLnVua25vd24gPSBUUlVFLCBGQVNUID0gVFJVRSkKcG9wX2luZm88LXJlYWQuY3N2KCIuLi9EYXRhL1NhbXBsZV9tZXRhZGF0YV84OTJwb3BzLmNzdiIpCnBvcHM8LXBvcF9pbmZvW3BvcF9pbmZvJHBvcD09IlBXUyIsXQoKI2Fzc2lnbiBncm91cHMKcG9wcyRncm91cDwtIkdyb3VwMSIKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIGM0JFNhbXBsZVtjNCRncm91cD09Ikdyb3VwMiJdXTwtIkdyb3VwMiIKcG9wcyRncm91cFtwb3BzJFNhbXBsZSAlaW4lIGM0JFNhbXBsZVtjNCRncm91cD09Ikdyb3VwMyJdXTwtIkdyb3VwMyIKcG9wdWxhdGlvbnMgPC0gc3BsaXQocG9wcyRTYW1wbGUsIHBvcHMkZ3JvdXApCnB3czwtc2V0LnBvcHVsYXRpb25zKHB3cywgcG9wdWxhdGlvbnMsIGRpcGxvaWQgPSBUKQoKIyBzZXQgdGhlIGNocm9tb3NvbWUgc2l6ZQpjaHJzaXplPC1yZWFkLnRhYmxlKCIuLi9EYXRhL25ld192Y2YvY2hyX3NpemVzLmJlZCIpCmNocjwtY2hyc2l6ZSRWM1tjaHJzaXplJFYxPT0iY2hyNCJdCgojIG1ha2UgYSBzbGlkaW5nIHdpbmRvdyBkYXRhc2V0CnB3c19zdyA8LSBzbGlkaW5nLndpbmRvdy50cmFuc2Zvcm0ocHdzLCB3aWR0aCA9IDUwMDAwLCBqdW1wID0gMTAwMDAsIHR5cGUgPSAyKQojIGNyYXRlIHNsaWRpbmcgd2luZG93IGluZm8Kd2luZG93czwtcHdzX3N3QHJlZ2lvbi5uYW1lcwp3aW5kb3dzPC1nc3ViKCIgIiwiIiwgd2luZG93cykKd2luZG93czwtZ3N1YigiOiIsIiIsd2luZG93cykKd2luZG93X3N0YXJ0PC1hcy5pbnRlZ2VyKHNhcHBseSh3aW5kb3dzLCBmdW5jdGlvbih4KSB1bmxpc3Qoc3Ryc3BsaXQoeCwgIi0iKSlbMV0pKQp3aW5kb3dfc3RvcDwtYXMuaW50ZWdlcihzYXBwbHkod2luZG93cywgZnVuY3Rpb24oeCkgdW5saXN0KHN0cnNwbGl0KHgsICItIikpWzJdKSkKd2luZG93PC1kYXRhLmZyYW1lKHN0YXJ0ID0gd2luZG93X3N0YXJ0LCBzdG9wID0gd2luZG93X3N0b3AsIAogICAgICAgICAgICAgICAgICAgICAgbWlkID0gd2luZG93X3N0YXJ0ICsgKHdpbmRvd19zdG9wLXdpbmRvd19zdGFydCkvMikKCiNjYWxjdWxhdGUgZGl2ZXJzaXR5IHN0YXRzCnB3c19zdyA8LSBkaXZlcnNpdHkuc3RhdHMocHdzX3N3LCBwaSA9IFRSVUUpCnB3c19zdyA8LSBGX1NULnN0YXRzKHB3c19zdywgbW9kZSA9ICJudWNsZW90aWRlIikKIyBleHRyYWN0IG51Y2xlb3RpZGUgZGl2ZXJzaXR5IGFuZCBjb3JyZWN0IGZvciB3aW5kb3cgc2l6ZQpuZCA8LSBwd3Nfc3dAbnVjLmRpdmVyc2l0eS53aXRoaW4vNTAwMDAKIyBtYWtlIGdyb3VwIG5hbWUgdmVjdG9yIGFuZCByZW5hbWUgdGhlIGNvbHVtbnMKZ3JvdXBuYW1lcyA8LSBzb3J0KHVuaXF1ZShwb3BzJGdyb3VwKSkKY29sbmFtZXMobmQpIDwtIHBhc3RlMChncm91cG5hbWVzLCAiX3BpIikKIyBleHRyYWN0IGZzdCB2YWx1ZXMKZnN0IDwtIHQocHdzX3N3QG51Yy5GX1NULnBhaXJ3aXNlKQojIGV4dHJhY3QgZHh5IC0gcGFpcndpc2UgYWJzb2x1dGUgbnVjbGVvdGlkZSBkaXZlcnNpdHkKZHh5IDwtIGdldC5kaXZlcnNpdHkocHdzX3N3LCBiZXR3ZWVuID0gVClbWzJdXS81MDAwMAojIHNldCB0aGUgY29sdW1uIG5hbWVzIAp4IDwtIGNvbG5hbWVzKGZzdCkKeCA8LSBzdWIoInBvcDEiLCBncm91cG5hbWVzWzFdLCB4KQp4IDwtIHN1YigicG9wMiIsIGdyb3VwbmFtZXNbMl0sIHgpCnggPC0gc3ViKCJwb3AzIiwgZ3JvdXBuYW1lc1szXSwgeCkKeCA8LSBzdWIoIi8iLCAiXyIsIHgpCgpjb2xuYW1lcyhmc3QpPC1wYXN0ZTAoImZzdF8iLHgpCmNvbG5hbWVzKGR4eSk8LXBhc3RlMCgiZHh5XyIseCkKCiNjb21iaW5lIGFsbCBkYXRhCnB3c19kYXRhIDwtIGFzX3RpYmJsZShkYXRhLmZyYW1lKHdpbmRvdywgbmQsIGZzdCwgZHh5KSkKd3JpdGUuY3N2KHB3c19kYXRhLCIuLi9PdXRwdXQvUENBL1BXU29ubHlfY2hyNF9wb3BnZW5vbWVfc3RhdHMuY3N2IikKCmNvbWI8LWNvbWJuKGdyb3VwbmFtZXMsIDIpCmNvbWI8LXQoY29tYikKZm9yIChpIGluIDE6IG5yb3coY29tYikpewogICAgICAgIHBvcDE8LWNvbWJbaSwxXQogICAgICAgIHBvcDI8LWNvbWJbaSwyXQogICAgICAgIGR0PC1wd3NfZGF0YVssIGMoIm1pZCIsIHBhc3RlMCgiZnN0XyIsIHBvcDEsIl8iLHBvcDIpLHBhc3RlMCgiZHh5XyIscG9wMSwiXyIscG9wMiksIHBhc3RlMChwb3AxLCJfcGkiKSxwYXN0ZTAocG9wMiwiX3BpIikpIF0KICAgICAgICBjb2xuYW1lcyhkdClbMjozXTwtYygiRnN0IiwiRHh5IikKICAgIAogICAgICAgIGR0X2c8LWdhdGhlcihkdCwgLW1pZCwga2V5ID0gInN0YXQiLCB2YWx1ZSA9ICJ2YWx1ZSIpCiAgICAgICAgZHRfZyRzdGF0PC1mYWN0b3IoZHRfZyRzdGF0LCBsZXZlbHM9YygiRnN0IiwiRHh5Iixjb2xuYW1lcyhkdClbNF0sIGNvbG5hbWVzKGR0KVs1XSkpCiAgICAgICAgZ2dwbG90KGR0X2csIGFlcyhtaWQvMTBeNiwgdmFsdWUsIGNvbG91ciA9IHN0YXQpKSArIGdlb21fbGluZSgpKwogICAgICAgICAgICBmYWNldF9ncmlkKHN0YXR+Liwgc2NhbGVzID0gImZyZWVfeSIpKwogICAgICAgICAgICB4bGFiKCJQb3NpdGlvbiAoTWIpIikreWxhYignJykrCiAgICAgICAgICAgIHRoZW1lX2xpZ2h0KCkgKyB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpK2dndGl0bGUocGFzdGUwKCJDaHI0ICIscG9wMSwiIHZzLiIsIHBvcDIpKSsKICAgICAgICAgICAgc2NhbGVfeF9jb250aW51b3VzKG1pbm9yX2JyZWFrcyA9IHNlcSgxLCBjaHIsMSApKQogICAgICAgIGdnc2F2ZShwYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyNF8iLHBvcDEsIiB2cy4iLCBwb3AyLCIucG5nIiksIHdpZHRoID0gOSwgaGVpZ2h0ID0gNCwgZHBpPTE1MCkKICAgIH0KYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfRGl2ZXJzaXR5X3N0YXRzX2NocjRfR3JvdXAxIHZzLkdyb3VwMi5wbmcpe3dpZHRoPTc1JX0KCiFbXSguLi9PdXRwdXQvUENBL1BXU29ubHlfRGl2ZXJzaXR5X3N0YXRzX2NocjRfR3JvdXAxIHZzLkdyb3VwMy5wbmcpe3dpZHRoPTc1JX0KIVtdKC4uL091dHB1dC9QQ0EvUFdTb25seV9EaXZlcnNpdHlfc3RhdHNfY2hyNF9Hcm91cDIgdnMuR3JvdXAzLnBuZyl7d2lkdGg9NzUlfQoKKiAqKlBXUyBncm91cHMgYXJlIHNlcGFyYXRlZCBieSB0aGVlbmQgb2YgdGhlIGNob3JvbXNvbWUgKD4yNy4zTWIpKioKCgojIyMgQ29tcGFyZSB0aGUgaGV0ZXJvenlnb3NpdHkgb2YgdGhlIHJlZ2lvbiBvZiBpbnRlcmVzdCAocmVnaW9uIDIgPjI3LjNNYikKCmBgYHtiYXNoIGV2YWw9RkFMU0V9CiNDYWxjdWxhdGUgaGV0ZXJvenlnb3NpdHkgcGVyIHdpbmRvdyB1c2luZyBiY2Z0b29scyAKIyAxLiBzdWJzZXQgVkNGIGJ5IGNocjIwIChoZXRfc3RhdHNfUFdTLmNoMjAuc2gpCmJjZnRvb2xzIHZpZXcgIC9ob21lL2t0aXN0L3BoL2RhdGEvbmV3X3ZjZi9NRDcwMDAvUFdTb25seV9OUzAuNV9tYWYwNS52Y2YuZ3ogLS1yZWdpb25zIGNocjQgPiAvaG9tZS9rdGlzdC9waC9kYXRhL25ld192Y2YvTUQ3MDAwL1BXU29ubHlfY2gyMF9tYWYwNS52Y2YKYmd6aXAgL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NoNF9tYWYwNS52Y2YKYmNmdG9vbHMgaW5kZXggL2hvbWUva3Rpc3QvcGgvZGF0YS9uZXdfdmNmL01ENzAwMC9QV1Nvbmx5X2NoNF9tYWYwNS52Y2YuZ3oKIzIuIFJ1biBoZXRfc3RhdHM0X1BXUy5zaCB0byBjYWxjdWxhdGUgaGV0IGluIHdpbmRvd3MKIzMuIENoYW5nZSB0aGUgZmlsZXMgdG8gdGFiLWRlbGltaXRlZCBhbmQgY2F0IHRoZW0KZm9yIGYgaW4gKjsgZG8gc2VkIC1pICJzLyQvXHQkZi8iICRmOyBkb25lIApjYXQgJChscyAtdCkgPiBQV1Nvbmx5X2NoNF9tYWYwNV9zdGF0c0ZpbGUKYGBgCgoKIyMjIFByb2Nlc3MgdGhlIHN0YXRzIGZpbGUgdG8gb2J0YWluIEhvIGFuZCBIZQoKYGBge3IgZWNobz1UUlVFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojIENhbGN1bGF0ZSBIbyBhbmQgSGUgZnJvbSBiY2Z0b29scyBzdGF0cyBvdXRwdXQgZmlsZXMgKHN0YXRzIGZyb20gUFdTb25seSBmaWxlcykKZGY8LXJlYWQudGFibGUoIi4uL0RhdGEvbmV3X3ZjZi9QV1Nvbmx5L1BXU29ubHlfY2g0X21hZjA1X3N0YXRzRmlsZSIsc2VwPSJcdCIsIGhlYWRlcj1GKQpkZjwtZGZbLGMoMzoxMCwgMTQ6MTUpXQpjb2xuYW1lcyhkZik8LWMoIlNhbXBsZSIsIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiLCAiblRyYW5zaXRpb25zIiwgIm5UcmFuc3ZlcnNpb25zIiwibkluZGVscyIsImF2ZXJhZ2UgZGVwdGgiLCJuTWlzc2luZyIsIndpbmRvd19ubyIpCmRmJHA8LSgyKmRmJG5SZWZIb20rZGYkbkhldHMpLyhyb3dTdW1zKGRmWyxjKCJuUmVmSG9tIiwibk5vblJlZkhvbSIsIm5IZXRzIildKSoyKQpkZiRxPC0oMipkZiRuTm9uUmVmSG9tK2RmJG5IZXRzKS8ocm93U3VtcyhkZlssYygiblJlZkhvbSIsIm5Ob25SZWZIb20iLCJuSGV0cyIpXSkqMikKICAgIApkZiRIZTwtMipkZiRwKmRmJHEKZGYkSG88LWRmJG5IZXRzL3Jvd1N1bXMoZGZbLGMoIm5SZWZIb20iLCJuTm9uUmVmSG9tIiwibkhldHMiKV0pCmhvPC1tZXJnZShkZiwgYzRbLGMoIlNhbXBsZSIsInBvcCIsInllYXIiLCJncm91cCIpXSwgYnk9IlNhbXBsZSIpCnllYXJzPC1jKDE5OTEsMTk5NiwyMDA3LDIwMTcpCgpIbzwtYWdncmVnYXRlKGhvWywiSG8iXSwgYnk9bGlzdChobyR3aW5kb3dfbm8saG8kZ3JvdXAsIGhvJHllYXIpLCBtZWFuLCBuYS5ybT1UICkKSGU8LWFnZ3JlZ2F0ZShob1ssIkhlIl0sIGJ5PWxpc3QoaG8kd2luZG93X25vLGhvJGdyb3VwLCBobyR5ZWFyKSwgbWVhbiwgbmEucm09VCApCmhldDwtY2JpbmQoSG8sIEhlJHgpCmNvbG5hbWVzKGhldCk8LWMoIndpbmRvd19pZCIsIkdyb3VwIiwieWVhciIsIkhvIiwiSGUiKQp3cml0ZS5jc3YoaGV0LHBhc3RlMCgiLi4vT3V0cHV0L1N0YXRzX3dpbmRvdy9QV1Nvbmx5X2NocjRfSGV0ZXJvX2J5R3JvdXAueWVhcl9tYWYwNS5jc3YiKSkKICAgIApoZXQkd2luZG93PC1hcy5pbnRlZ2VyKGdzdWIocGFzdGUwKCJQV1NfY2g0X3N0YXRzXyIpLCcnLGhldCR3aW5kb3dfaWQpKQpoZXQkbG9jPC0icmVnaW9uMSIKaGV0JGxvY1toZXQkd2luZG93PjI3M108LSJyZWdpb24yIgogICAgCmdyb3VwSG88LWFnZ3JlZ2F0ZShoZXRbLCJIbyJdLCBieT1saXN0KGhldCRHcm91cCwgaGV0JGxvYywgaGV0JHllYXIpLCBtZWFuICwgbmEucm09VCkKY29sbmFtZXMoZ3JvdXBIbyk8LWMoIkdyb3VwIiwiUmVnaW9uIiwiWWVhciIsIkhvIikKd3JpdGUuY3N2KGdyb3VwSG8sICIuLi9PdXRwdXQvU3RhdHNfd2luZG93L1BXU29ubHlfY2hyNF9IZXRlcm9fZ3JvdXBfc3VtbWFyeS5jc3YiKQpgYGAKCiMjIyBDb21wYXJlIEhldGVyb3p5Z29zaXR5IGxldmVscyBhbW9uZyBncm91cHMgYW5kIGJldHdlZW4gcmVnaW9ucwpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojQ3JlYXRlIGEgZmlndXJlCmdjb2xzPC1jKCIjRkI2ODdCIiwiIzQ4QUJFMyIsIiM3NUJBNzYiKQoKZ2dwbG90KCkrCiAgICBnZW9tX2JveHBsb3QoZGF0YT1oZXQsYWVzKHg9bG9jLCB5PUhvLCBjb2xvcj1Hcm91cCwgZmlsbD1Hcm91cCksIHBvc2l0aW9uPXBvc2l0aW9uX2RvZGdlKHdpZHRoID0wLjgpLG91dGxpZXIuYWxwaGEgPSAwLjYsIG91dGxpZXIuc2l6ZSA9IDEsd2lkdGg9MC43KSsKICAgIGdlb21fcG9pbnQoZGF0YT1ncm91cEhvLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICBmYWNldF93cmFwKH55ZWFyKSsKICAgIHRoZW1lX21pbmltYWwoKSsKICAgIHRoZW1lKHBhbmVsLmdyaWQubWFqb3IueCA9IGVsZW1lbnRfYmxhbmsoKSkrCiAgICBnZW9tX3ZsaW5lKHhpbnRlcmNlcHQgPSBjKDEuNSksIGNvbG9yPSJncmF5NzAiLHNpemU9MC4zKSsKICAgIHNjYWxlX2NvbG9yX21hbnVhbCh2YWx1ZXM9Z2NvbHMpKwogICAgc2NhbGVfZmlsbF9tYW51YWwodmFsdWVzPXBhc3RlMChnY29scywgIjY2IikpK3hsYWIoJycpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1NfQ2hyMTVfSG8uaW4udHdvcmVnaW9uc19ieVllYXJzLnBuZyIsIHdpZHRoID0gOCwgaGVpZ2h0ID0gNywgZHBpPTMwMCkKCiNhbGwgeWVhcnMgdG9nZXRoZXIKZ3JvdXBIbzI8LWFnZ3JlZ2F0ZShoZXRbLCJIbyJdLCBieT1saXN0KGhldCRHcm91cCwgaGV0JGxvYyksIG1lYW4gLCBuYS5ybT1UKQpjb2xuYW1lcyhncm91cEhvMik8LWMoIkdyb3VwIiwiUmVnaW9uIiwiSG8iKQpnZ3Bsb3QoKSsKICAgIGdlb21fYm94cGxvdChkYXRhPWhldCxhZXMoeD1sb2MsIHk9SG8sIGNvbG9yPUdyb3VwLCBmaWxsPUdyb3VwKSwgcG9zaXRpb249cG9zaXRpb25fZG9kZ2Uod2lkdGggPTAuOCksb3V0bGllci5hbHBoYSA9IDAuNiwgb3V0bGllci5zaXplID0gMSx3aWR0aD0wLjcpKwogICAgZ2VvbV9wb2ludChkYXRhPWdyb3VwSG8yLCBhZXMoeD1SZWdpb24sIHk9SG8sIGNvbG9yPUdyb3VwKSxwb3NpdGlvbj1wb3NpdGlvbl9kb2RnZSh3aWR0aCA9MC44KSkrCiAgICB0aGVtZV9taW5pbWFsKCkrCiAgICB0aGVtZShwYW5lbC5ncmlkLm1ham9yLnggPSBlbGVtZW50X2JsYW5rKCkpKwogICAgZ2VvbV92bGluZSh4aW50ZXJjZXB0ID0gYygxLjUpLCBjb2xvcj0iZ3JheTcwIixzaXplPTAuMykrCiAgICBzY2FsZV9jb2xvcl9tYW51YWwodmFsdWVzPWdjb2xzKSsKICAgIHNjYWxlX2ZpbGxfbWFudWFsKHZhbHVlcz1wYXN0ZTAoZ2NvbHMsICI2NiIpKSt4bGFiKCcnKStnZ3RpdGxlKCJDaHIyMCIpCmdnc2F2ZSgiLi4vT3V0cHV0L1BDQS9QV1NfQ2hyMjBfSG8uaW4udHdvcmVnaW9ucy5wbmciLCB3aWR0aCA9IDYsIGhlaWdodCA9IDQsIGRwaT0zMDApCgpgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTX0NocjIwX0hvLmluLnR3b3JlZ2lvbnMucG5nKXt3aWR0aD02MCV9CgohW10oLi4vT3V0cHV0L1BDQS9QV1NfQ2hyNF9Iby5pbi50d29yZWdpb25zX2J5WWVhcnMucG5nKXt3aWR0aD03MCV9CgojIyBMb29rIGF0IHRoZSBvdmVybGFwIG9mIGluZGl2aWR1YWxzIAojIyMgQmV3ZWVuIEdyb3VwMyAmIEdyb3VwMiBhbW9uZyBDaHIyMCwgQ2hyMTUsIENocjgsIGFuZCBDaHI0IChQV1Nvbmx5KQoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NoMTUgYWRuIGNoOCBncm91cGluZ3MgYXJlIHRoZSBzYW1lIGZvciBQV1Nvbmx5IGFuZCBQV1Mrb3RoZXIgcG9wcwpjMTU8LXJlYWQuY3N2KCIuLi9PdXRwdXQvUENBL2NocjE1X1BDQWdyb3Vwcy5jc3YiLCByb3cubmFtZXMgPSAxKQpjMTU8LWMxNVtjMTUkcG9wPT0iUFdTIixdCmM4PC1yZWFkLmNzdigiLi4vT3V0cHV0L1BDQS9QV1Nvbmx5X3dpdGguZ3JvdXBzX3BjYV9jaHI4LmNzdiIsIHJvdy5uYW1lcyA9IDEpCgpjMTVnMzwtYzE1JFNhbXBsZVtjMTUkR3JvdXA9PSJHcm91cDMiXQpjOGczPC1jOCRTYW1wbGVbYzgkZ3JvdXA9PSJHcm91cDMiXQpjMjBnMzwtYzIwJFNhbXBsZVtjMjAkZ3JvdXA9PSJHcm91cDMiXQpjNGczPC1jNCRTYW1wbGVbYzQkZ3JvdXA9PSJHcm91cDMiXQoKeDwtbGlzdChjaHI0PWM0ZzMsIGNocjg9YzhnMyxjaHIxNT1jMTVnMywgY2hyMjA9YzIwZzMpCnAzPC1nZ3Zlbm4oeCwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKCmMxNWcyPC1jMTUkU2FtcGxlW2MxNSRHcm91cD09Ikdyb3VwMiJdCmM4ZzI8LWM4JFNhbXBsZVtjOCRncm91cD09Ikdyb3VwMiJdCmMyMGcyPC1jMjAkU2FtcGxlW2MyMCRncm91cD09Ikdyb3VwMiJdCmM0ZzI8LWM0JFNhbXBsZVtjNCRncm91cD09Ikdyb3VwMiJdCgp4MjwtbGlzdChjaHI0PWM0ZzIsIGNocjg9YzhnMixjaHIxNT1jMTVnMiwgY2hyMjA9YzIwZzIpCnAyPC1nZ3Zlbm4oeDIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCgpjMTVnMTwtYzE1JFNhbXBsZVtjMTUkR3JvdXA9PSJHcm91cDEiXQpjOGcxPC1jOCRTYW1wbGVbYzgkZ3JvdXA9PSJHcm91cDEiXQpjMjBnMTwtYzIwJFNhbXBsZVtjMjAkZ3JvdXA9PSJHcm91cDEiXQpjNGcxPC1jNCRTYW1wbGVbYzQkZ3JvdXA9PSJHcm91cDEiXQp4MTwtbGlzdChjaHI0PWM0ZzEsIGNocjg9YzhnMSxjaHIxNT1jMTVnMSwgY2hyMjA9YzIwZzEpCnAxPC1nZ3Zlbm4oeDEsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMSIpCgp2ZW5uPC1nZ2RyYXcoKSsKICAgICAgICBkcmF3X3Bsb3QocDEseD0wLHk9MCx3aWR0aD0wLjMzLGhlaWdodD0xKSsKICAgICAgICBkcmF3X3Bsb3QocDIseD0wLjMzLHk9MCx3aWR0aD0wLjMzLGhlaWdodD0xKSsKICAgICAgICBkcmF3X3Bsb3QocDMsMC42NiwwLDAuMzMsMSkrCiAgICAgICAgZHJhd19wbG90X2xhYmVsKCJQV1MiLCB4PS0wLjAxLCB5PTAuOTUsIHNpemUgPSAxNSkKc2F2ZV9wbG90KGZpbGVuYW1lID1wYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTX2NoNC44LjE1LjIwLmdyb3VwX292ZXJsYXAucG5nIiksIHBsb3QgPSB2ZW5uLGJhc2Vfd2lkdGggPSAxMCwgYmFzZV9oZWlnaHQgPSA1LCBkcGk9MzAwKSAgIApgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTX2NoNC44LjE1LjIwLmdyb3VwX292ZXJsYXAucG5nKQoKCiMjIyBQYWlyd2lzZSBjb21wYXJpc29uCgojIyMjIGNocjQgdnMuIGNocjgKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiN4PC1saXN0KGNocjQ9YzRnMywgY2hyOD1jOGczLGNocjE1PWMxNWczLCBjaHIyMD1jMjBnMykKI3gyPC1saXN0KGNocjQ9YzRnMiwgY2hyOD1jOGcyLGNocjE1PWMxNWcyLCBjaHIyMD1jMjBnMikKeC4xPC1saXN0KGNocjQ9YzRnMywgY2hyOD1jOGczKQpwMzwtZ2d2ZW5uKHguMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKCngyLjI8LWxpc3QoY2NocjQ9YzRnMiwgY2hyOD1jOGcyKQpwMjwtZ2d2ZW5uKHgyLjIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCngxLjE8LWxpc3QoY2hyND1jNGcxLCBjaHI4PWM4ZzEpCnAxPC1nZ3Zlbm4oeDEuMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAxIikKCnZlbm48LWdnZHJhdygpKwogICAgICAgIGRyYXdfcGxvdChwMSx4PTAseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMix4PTAuMzMseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMywwLjY2LDAsMC4zMywxKSsKICAgICAgICBkcmF3X3Bsb3RfbGFiZWwoIlBXUyBjaHI0IHZzLiBjaHI4IiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDQuOC5ncm91cF9vdmVybGFwLnBuZyIpLCBwbG90ID0gdmVubixiYXNlX3dpZHRoID0gNywgYmFzZV9oZWlnaHQgPSA1LCBkcGk9MzAwKSAgIApgYGAKIVtdKC4uL091dHB1dC9QQ0EvUFdTX2NoNC44Lmdyb3VwX292ZXJsYXAucG5nKQoKCgojIyMjIGNocjQgdnMuIGNocjE1CgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojeDwtbGlzdChjaHI0PWM0ZzMsIGNocjg9YzhnMyxjaHIxNT1jMTVnMywgY2hyMjA9YzIwZzMpCiN4MjwtbGlzdChjaHI0PWM0ZzIsIGNocjg9YzhnMixjaHIxNT1jMTVnMiwgY2hyMjA9YzIwZzIpCnguMTwtbGlzdChjaHI0PWM0ZzMsIGNocjE1PWMxNWczKQpwMzwtZ2d2ZW5uKHguMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKeDIuMjwtbGlzdChjaHI0PWM0ZzIsIGNocjE1PWMxNWcyKQpwMjwtZ2d2ZW5uKHgyLjIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCngxLjE8LWxpc3QoY2hyND1jNGcxLCBjaHIxNT1jMTVnMSkKcDE8LWdndmVubih4MS4xLCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDEiKQoKdmVubjwtZ2dkcmF3KCkrCiAgICAgICAgZHJhd19wbG90KHAxLHg9MCx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAyLHg9MC4zMyx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAzLDAuNjYsMCwwLjMzLDEpKwogICAgICAgIGRyYXdfcGxvdF9sYWJlbCgiUFdTIGNocjQgdnMuIGNocjE1IiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDQuMTUuZ3JvdXBfb3ZlcmxhcC5wbmciKSwgcGxvdCA9IHZlbm4sYmFzZV93aWR0aCA9IDcsIGJhc2VfaGVpZ2h0ID0gNSwgZHBpPTMwMCkgICAKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDQuMTUuZ3JvdXBfb3ZlcmxhcC5wbmcpCgojIyMjIGNocjQgdnMuIGNocjIwKGVuZC1ncm91cHMpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp4LjE8LWxpc3QoY2hyND1jNGczLGNocjIwPWMyMGczKQpwMzwtZ2d2ZW5uKHguMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKeDIuMjwtbGlzdChjaHI0PWM0ZzIsIGNocjIwPWMyMGcyKQpwMjwtZ2d2ZW5uKHgyLjIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCngxLjE8LWxpc3QoY2hyND1jNGcxLCBjaHIyMD1jMjBnMSkKcDE8LWdndmVubih4MS4xLCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDEiKQoKdmVubjwtZ2dkcmF3KCkrCiAgICAgICAgZHJhd19wbG90KHAxLHg9MCx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAyLHg9MC4zMyx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAzLDAuNjYsMCwwLjMzLDEpKwogICAgICAgIGRyYXdfcGxvdF9sYWJlbCgiUFdTIGNocjQgdnMuIGNocjIwKGVuZCkiLCB4PS0wLjAxLCB5PTAuOTUsIHNpemUgPSAxNSkKc2F2ZV9wbG90KGZpbGVuYW1lID1wYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTX2NoNC4yMC5ncm91cF9vdmVybGFwLnBuZyIpLCBwbG90ID0gdmVubixiYXNlX3dpZHRoID0gNywgYmFzZV9oZWlnaHQgPSA1LCBkcGk9MzAwKSAgIApgYGAKCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDQuMjAuZ3JvdXBfb3ZlcmxhcC5wbmcpCgojIyMjIGNocjE1IHZzLiBjaHIyMChlbmQpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQp4LjE8LWxpc3QoY2hyMTU9YzE1ZzMsIGNocjIwPWMyMGczKQpwMzwtZ2d2ZW5uKHguMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKCngyLjI8LWxpc3QoY2hyMTU9YzE1ZzIsIGNocjIwPWMyMGcyKQpwMjwtZ2d2ZW5uKHgyLjIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCngxLjE8LWxpc3QoY2hyMTU9YzE1ZzEsY2hyMjA9YzIwZzEpCnAxPC1nZ3Zlbm4oeDEuMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAxIikKCnZlbm48LWdnZHJhdygpKwogICAgICAgIGRyYXdfcGxvdChwMSx4PTAseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMix4PTAuMzMseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMywwLjY2LDAsMC4zMywxKSsKICAgICAgICBkcmF3X3Bsb3RfbGFiZWwoIlBXUyBjaHIxNSB2cy4gY2hyMjAiLCB4PS0wLjAxLCB5PTAuOTUsIHNpemUgPSAxNSkKc2F2ZV9wbG90KGZpbGVuYW1lID1wYXN0ZTAoIi4uL091dHB1dC9QQ0EvUFdTX2NoMTUuMjAuZ3JvdXBfb3ZlcmxhcC5wbmciKSwgcGxvdCA9IHZlbm4sYmFzZV93aWR0aCA9IDcsIGJhc2VfaGVpZ2h0ID0gNSwgZHBpPTMwMCkgICAKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDE1LjIwLmdyb3VwX292ZXJsYXAucG5nKQoKIyMjIyBjaHI4IHZzLiBjaHIyMChlbmQpCgpgYGB7ciBldmFsPUZBTFNFLCBtZXNzYWdlPUZBTFNFLCB3YXJuaW5nPUZBTFNFfQojeDwtbGlzdChjaHI0PWM0ZzMsIGNocjg9YzhnMyxjaHIxNT1jMTVnMywgY2hyMjA9YzIwZzMpCiN4MjwtbGlzdChjaHI0PWM0ZzIsIGNocjg9YzhnMixjaHIxNT1jMTVnMiwgY2hyMjA9YzIwZzIpCnguMTwtbGlzdChjaHI4PWM4ZzMsIGNocjIwPWMyMGczKQpwMzwtZ2d2ZW5uKHguMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKeDIuMjwtbGlzdChjaHI4PWM4ZzIsY2hyMjA9YzIwZzIpCnAyPC1nZ3Zlbm4oeDIuMiwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAyIikKeDEuMTwtbGlzdChjaHI4PWM4ZzEsY2hyMjA9YzIwZzEpCnAxPC1nZ3Zlbm4oeDEuMSwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAxIikKCnZlbm48LWdnZHJhdygpKwogICAgICAgIGRyYXdfcGxvdChwMSx4PTAseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMix4PTAuMzMseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMywwLjY2LDAsMC4zMywxKSsKICAgICAgICBkcmF3X3Bsb3RfbGFiZWwoIlBXUyBjaHI4IHZzLiBjaHIyMChlbmQpIiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDguMjBlbmQuZ3JvdXBfb3ZlcmxhcC5wbmciKSwgcGxvdCA9IHZlbm4sYmFzZV93aWR0aCA9IDcsIGJhc2VfaGVpZ2h0ID0gNSwgZHBpPTMwMCkgICAKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDguMjBlbmQuZ3JvdXBfb3ZlcmxhcC5wbmcpCgoKIyMjIGNocjIwIGdyb3VwaW5nIHdpdGggaW52ZXJzaW9uIGNsdXN0ZXJzIAoKYGBge3IgZXZhbD1GQUxTRSwgbWVzc2FnZT1GQUxTRSwgd2FybmluZz1GQUxTRX0KI2NoMTUgYWRuIGNoOCBncm91cGluZ3MgYXJlIHRoZSBzYW1lIGZvciBQV1Nvbmx5IGFuZCBQV1Mrb3RoZXIgcG9wcwpjMjBjMzwtcGNhMjAkU2FtcGxlW3BjYTIwJEdyb3VwPT0iR3JvdXAzIl0KeDwtbGlzdChjaHI0PWM0ZzMsIGNocjg9YzhnMyxjaHIxNT1jMTVnMywgY2hyMjA9YzIwYzMpCnAzPC1nZ3Zlbm4oeCwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAzIikKCmMyMGMyPC1wY2EyMCRTYW1wbGVbcGNhMjAkR3JvdXA9PSJHcm91cDIiXQp4MjwtbGlzdChjaHI0PWM0ZzIsIGNocjg9YzhnMixjaHIxNT1jMTVnMiwgY2hyMjA9YzIwYzIpCnAyPC1nZ3Zlbm4oeDIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMiIpCgpjMjBjMTwtcGNhMjAkU2FtcGxlW3BjYTIwJEdyb3VwPT0iR3JvdXAxIl0KeDE8LWxpc3QoY2hyND1jNGcxLCBjaHI4PWM4ZzEsY2hyMTU9YzE1ZzEsIGNocjIwPWMyMGMxKQpwMTwtZ2d2ZW5uKHgxLCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDEiKQoKdmVubjwtZ2dkcmF3KCkrCiAgICAgICAgZHJhd19wbG90KHAxLHg9MCx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAyLHg9MC4zMyx5PTAsd2lkdGg9MC4zMyxoZWlnaHQ9MSkrCiAgICAgICAgZHJhd19wbG90KHAzLDAuNjYsMCwwLjMzLDEpKwogICAgICAgIGRyYXdfcGxvdF9sYWJlbCgiUFdTIENocjIwIGludmVyc2lvbiBjbHVzdGVyIiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDQuOC4xNS5ncm91cCsyMGNsdXN0ZXJfb3ZlcmxhcC5wbmciKSwgcGxvdCA9IHZlbm4sYmFzZV93aWR0aCA9IDEwLCBiYXNlX2hlaWdodCA9IDUsIGRwaT0zMDApICAgCmBgYAohW10oLi4vT3V0cHV0L1BDQS9QV1NfY2g0LjguMTUuZ3JvdXArMjBjbHVzdGVyX292ZXJsYXAucG5nKQoKIyMjIyBjaHI0IHZzLiBjaHIyMF9pbnYKCmBgYHtyIGV2YWw9RkFMU0UsIG1lc3NhZ2U9RkFMU0UsIHdhcm5pbmc9RkFMU0V9CiN4PC1saXN0KGNocjQ9YzRnMywgY2hyOD1jOGczLGNocjE1PWMxNWczLCBjaHIyMD1jMjBnMykKI3gyPC1saXN0KGNocjQ9YzRnMiwgY2hyOD1jOGcyLGNocjE1PWMxNWcyLCBjaHIyMD1jMjBnMikKeC4xPC1saXN0KGNocjQ9YzRnMywgY2hyMjA9YzIwYzMpCnAzPC1nZ3Zlbm4oeC4xLCBmaWxsX2NvbG9yID0gY29scywgc3Ryb2tlX3NpemUgPSAwLjUsIHNldF9uYW1lX3NpemUgPSA0LHRleHRfc2l6ZT0zKStnZ3RpdGxlKCJHcm91cDMiKQp4Mi4yPC1saXN0KGNocjQ9YzRnMiwgY2hyMjA9YzIwYzIpCnAyPC1nZ3Zlbm4oeDIuMiwgZmlsbF9jb2xvciA9IGNvbHMsIHN0cm9rZV9zaXplID0gMC41LCBzZXRfbmFtZV9zaXplID0gNCx0ZXh0X3NpemU9MykrZ2d0aXRsZSgiR3JvdXAyIikKeDEuMjwtbGlzdChjaHI0PWM0ZzEsIGNocjIwPWMyMGMxKQpwMTwtZ2d2ZW5uKHgxLjIsIGZpbGxfY29sb3IgPSBjb2xzLCBzdHJva2Vfc2l6ZSA9IDAuNSwgc2V0X25hbWVfc2l6ZSA9IDQsdGV4dF9zaXplPTMpK2dndGl0bGUoIkdyb3VwMSIpCgp2ZW5uPC1nZ2RyYXcoKSsKICAgICAgIGRyYXdfcGxvdChwMSx4PTAseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMix4PTAuMzMseT0wLHdpZHRoPTAuMzMsaGVpZ2h0PTEpKwogICAgICAgIGRyYXdfcGxvdChwMywwLjY2LDAsMC4zMywxKSsKICAgICAgICBkcmF3X3Bsb3RfbGFiZWwoIlBXUyBjaHI0IHZzLiBjaHIyMChpbnYpIiwgeD0tMC4wMSwgeT0wLjk1LCBzaXplID0gMTUpCnNhdmVfcGxvdChmaWxlbmFtZSA9cGFzdGUwKCIuLi9PdXRwdXQvUENBL1BXU19jaDQuMjBpbnYuZ3JvdXBfb3ZlcmxhcC5wbmciKSwgcGxvdCA9IHZlbm4sYmFzZV93aWR0aCA9IDcsIGJhc2VfaGVpZ2h0ID0gNSwgZHBpPTMwMCkgICAKYGBgCiFbXSguLi9PdXRwdXQvUENBL1BXU19jaDQuMjBpbnYuZ3JvdXBfb3ZlcmxhcC5wbmcpCgo=